Interface type check with Typescript

前端 未结 17 985
灰色年华
灰色年华 2020-11-22 14:09

This question is the direct analogon to Class type check with TypeScript

I need to find out at runtime if a variable of type any implements an interface. Here\'s my

相关标签:
17条回答
  • 2020-11-22 14:33

    How about User-Defined Type Guards? https://www.typescriptlang.org/docs/handbook/advanced-types.html

    interface Bird {
        fly();
        layEggs();
    }
    
    interface Fish {
        swim();
        layEggs();
    }
    
    function isFish(pet: Fish | Bird): pet is Fish { //magic happens here
        return (<Fish>pet).swim !== undefined;
    }
    
    // Both calls to 'swim' and 'fly' are now okay.
    
    if (isFish(pet)) {
        pet.swim();
    }
    else {
        pet.fly();
    }
    
    0 讨论(0)
  • 2020-11-22 14:33
    export interface ConfSteps {
        group: string;
        key: string;
        steps: string[];
    }
    
    private verify(): void {
        const obj = `{
          "group": "group",
          "key": "key",
          "steps": [],
          "stepsPlus": []
        } `;
        if (this.implementsObject<ConfSteps>(obj, ['group', 'key', 'steps'])) {
          console.log(`Implements ConfSteps: ${obj}`);
        }
      }
    
    private objProperties: Array<string> = [];
    
    private implementsObject<T>(obj: any, keys: (keyof T)[]): boolean {
        JSON.parse(JSON.stringify(obj), (key, value) => {
          this.objProperties.push(key);
        });
        for (const key of keys) {
          if (!this.objProperties.includes(key.toString())) {
            return false;
          }
        }
        this.objProperties = null;
        return true;
      }
    
    0 讨论(0)
  • 2020-11-22 14:33

    Type guards in Typescript:

    TS has type guards for this purpose. They define it in the following manner:

    Some expression that performs a runtime check that guarantees the type in some scope.

    This basically means that the TS compiler can narrow down the type to a more specific type when it has sufficient information. For example:

    function foo (arg: number | string) {
        if (typeof arg === 'number') {
            // fine, type number has toFixed method
            arg.toFixed()
        } else {
            // Property 'toFixed' does not exist on type 'string'. Did you mean 'fixed'?
            arg.toFixed()
            // TSC can infer that the type is string because 
            // the possibility of type number is eliminated at the if statement
        }
    }
    

    To come back to your question, we can also apply this concept of type guards to objects in order to determine their type. To define a type guard for objects, we need to define a function whose return type is a type predicate. For example:

    interface Dog {
        bark: () => void;
    }
    
    // The function isDog is a user defined type guard
    // the return type: 'pet is Dog' is a type predicate, 
    // it determines whether the object is a Dog
    function isDog(pet: object): pet is Dog {
      return (pet as Dog).bark !== undefined;
    }
    
    const dog: any = {bark: () => {console.log('woof')}};
    
    if (isDog(dog)) {
        // TS now knows that objects within this if statement are always type Dog
        // This is because the type guard isDog narrowed down the type to Dog
        dog.bark();
    }
    
    0 讨论(0)
  • 2020-11-22 14:35

    same as above where user-defined guards were used but this time with an arrow function predicate

    interface A {
      member:string;
    }
    
    const check = (p: any): p is A => p.hasOwnProperty('member');
    
    var foo: any = { member: "foobar" };
    if (check(foo))
        alert(foo.member);
    
    0 讨论(0)
  • 2020-11-22 14:35

    TypeGuards

    interface MyInterfaced {
        x: number
    }
    
    function isMyInterfaced(arg: any): arg is MyInterfaced {
        return arg.x !== undefined;
    }
    
    if (isMyInterfaced(obj)) {
        (obj as MyInterfaced ).x;
    }
    
    0 讨论(0)
  • 2020-11-22 14:40

    It's now possible, I just released an enhanced version of the TypeScript compiler that provides full reflection capabilities. You can instantiate classes from their metadata objects, retrieve metadata from class constructors and inspect interface/classes at runtime. You can check it out here

    Usage example:

    In one of your typescript files, create an interface and a class that implements it like the following:

    interface MyInterface {
        doSomething(what: string): number;
    }
    
    class MyClass implements MyInterface {
        counter = 0;
    
        doSomething(what: string): number {
            console.log('Doing ' + what);
            return this.counter++;
        }
    }
    

    now let's print some the list of implemented interfaces.

    for (let classInterface of MyClass.getClass().implements) {
        console.log('Implemented interface: ' + classInterface.name)
    }
    

    compile with reflec-ts and launch it:

    $ node main.js
    Implemented interface: MyInterface
    Member name: counter - member kind: number
    Member name: doSomething - member kind: function
    

    See reflection.d.ts for Interface meta-type details.

    UPDATE: You can find a full working example here

    0 讨论(0)
提交回复
热议问题