Intro
When I code with TypeScript, I often check the type of variables or arguments of functions.
Most of them are null checking. But others are more complicated.
Because I want to know how the type checking becomes more simple, I will try type checking of TypeScript.
typeof
If the target type belongs object types like "string", "number", etc., I can use "typeof" operator for type checking.
Because TypeScript has type guards, I can treat the argument as string value.
function check(target: any): boolean {
if(typeof target === "string") {
console.log(target.toUpperCase());
return true;
}
return false;
}
instanceof
If the target type is class, I can use "instanceof" operator.
class ClassSample {
public id = -1;
public name = 'Hello';
public greet(message: string): void {
console.log(`${message}`);
}
}
export function init(): void {
const c = new ClassSample();
const checkResult = check(c);
// CHECK true
console.log(`CHECK ${checkResult}`);
}
function check(value: any): boolean {
if(value instanceof ClassSample) {
// "value" is treated as ClassSample
value.greet('Hello');
return true;
}
return false;
}
This operator checks types by prototype property.
class ClassSample {
public id = -1;
public name = 'Hello';
public greet(message: string): void {
console.log(`${message}`);
}
}
class ClassSample2 extends ClassSample {
public greet2(message: string): void {
console.log(`${message}`);
}
}
type TypeSample = {
id: number,
name: string,
greet: (message: string) => void,
};
export function init(): void {
const c = new ClassSample();
const c2 = new ClassSample2();
const t: TypeSample = {
id: 3,
name: 'world',
greet: (message: string) => alert(message),
};
const checkResult = check(c);
// CHECK true
console.log(`CHECK ${checkResult}`);
// extended class also get true
const checkResult2 = check(c2);
// CHECK true
console.log(`CHECK2 ${checkResult2}`);
// "instanceof" isn't check the properties
const checkResult3 = check(t);
// CHECK false
console.log(`CHECK3 ${checkResult3}`);
}
...
Check types or interfaces
I can't use "typeof" and "instanceof" to check "type" or "interface".
Because all of the return values of "typeof" are "object".
And because JavaScript doesn't has "type" and "interface", I can't use "instanceof".
So I have to use custom type guards.
...
function check(value: any): boolean {
if(checkTypeSample(value)) {
return true;
}
return false;
}
function checkTypeSample(value: any): value is TypeSample {
if(typeof value !== 'object') {
return false;
}
// check the property exists by "in" operator
if('id' in value === false) {
return false;
}
if(typeof value.id !== 'number') {
return false;
}
if('name' in value === false) {
return false;
}
if(typeof value.name !== 'string') {
return false;
}
if('greet' in value === false) {
return false;
}
if(typeof value.greet !== 'function') {
return false;
}
return true;
}
If the return value of "checkTypeSample" is true, I can treat the value as "TypeSample".
Check functions?
One problem is I only can check the function in two ways.
- The function name is 'greet'
- The type of function is 'function'
So after I add another type like below, I can't distinguish them with "checkTypeSample".
...
type TypeSample = {
id: number,
name: string,
greet: (message: string) => void,
};
type TypeSample2 = {
id: number,
name: string,
greet: (id: number, message: string) => void,
};
export function init(): void {
const t: TypeSample = {
id: 3,
name: 'world',
greet: (message: string) => alert(message),
};
const t2: TypeSample2 = {
id: 4,
name: 'Hello world',
greet: (id: number, name: string) => console.log(`Hello ${id}:${name}`),
};
// T result:true
console.log(`T result:${checkTypeSample(t)}`);
// T2 result:true
console.log(`T2 result:${checkTypeSample(t2)}`);
}
...
Get arguments
Unfortunately "Function.arguments" can no longer be used.
After all, I get a string value of the function and split text to get arguments.
...
function checkTypeSample(value: any): value is TypeSample {
...
if('greet' in value === false) {
return false;
}
if(typeof value.greet !== 'function') {
return false;
}
// (message) => alert(message)
const greetText = value.greet.toString();
// if the number of arguments is more than 2, I should use "/\([0-9|a-z|A-Z|,|\s]+\)/g"
const splittedGreetTexts = greetText.match(/\([0-9|a-z|A-Z]+\)/g);
// I can only check the number of arguments of the function.
if(splittedGreetTexts == null ||
splittedGreetTexts.length <= 0 ||
splittedGreetTexts[0] == null) {
return false;
}
return true;
}
Top comments (0)