DEV Community

Masui Masanori
Masui Masanori

Posted on

[TypeScript] Type check

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;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

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;
}
Enter fullscreen mode Exit fullscreen mode

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}`);
}
...
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

If the return value of "checkTypeSample" is true, I can treat the value as "TypeSample".
Alt Text

Check functions?

One problem is I only can check the function in two ways.

  1. The function name is 'greet'
  2. 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)}`);
}
...
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)