[タイプスクリプト]タイプチェック


イントロ


私がtypescriptでコード化するとき、私はしばしば変数のタイプまたは関数の引数をチェックします.
それらのほとんどはNULLチェックです.しかし、他のものはより複雑です.
タイプチェックがより簡単になる方法を知りたいので、タイプスクリプトのタイプチェックを試みます.

タイプ


ターゲット型が“string”や“number”などのオブジェクト型に属している場合、type checkの“typeof”演算子を使用できます.
タイプスクリプトにはタイプガードがあるので、引数を文字列値として扱うことができます.
function check(target: any): boolean {
    if(typeof target === "string") {
        console.log(target.toUpperCase());        
        return true;
    }
    return false;
}
  • Typeof Type Operator - TypeScript Documentation
  • インターン


    ターゲット型がクラスの場合、“instanceof”演算子を使用できます.
    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;
    }
    
    この演算子は、プロトタイププロパティで型をチェックします.
    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}`);
    }
    ...
    
  • instanceof - JavaScript|MDN
  • チェックの種類またはインターフェイス


    「typeof」と「instanceof」を使うことはできません.
    「typeof」の戻り値の全てが「オブジェクト」であるので.
    JavaScriptが“type”と“interface”を持っていないので、“instanceof”を使うことはできません.
    だから、私はカスタムタイプのガードを使用する必要があります.
    ...
    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;
    }
    
    “CheckTypesAmple”の戻り値がtrueの場合、値を“typesample”として扱うことができます.
  • Narrowing - TypeScript Documentation
  • Type Guard - TypeScript Deep Dive
  • チェック機能?


    つの問題は、私は2つの方法で機能をチェックすることができます.
  • 関数名は' greet 'です
  • 関数の型は' function 'です
  • それで、以下のような別のタイプを追加した後、“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)}`);
    }
    ...
    

    引数を得る


    残念ながら“function .引数”はもはや使用できません.
  • Function.arguments - JavaScript|MDN
  • 結局、関数の文字列値を取得し、引数を得るためにテキストを分割します.
    ...
    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;
    }