代码之家  ›  专栏  ›  技术社区  ›  Aeseir

检查接口类型

  •  0
  • Aeseir  · 技术社区  · 5 年前

    我想实现一个泛型方法,根据对象的接口返回一个包含的值。然而,我不知道如何实现它,我已经研究了typeof和interfaceof,但不确定如何实现它以满足下面的逻辑。

    例如

    export interface Animal {
      name: string;
    }
    
    export interface Vehicle {
      model: string;
    }
    
    getDesignation<T>(data: T): string {
    
    // if data has ANIMAL interface on it
    // return data.name;
    
    // if data has VEHICLE interface on it
    // return data.model;
    }
    

    工作代码的示例如下:

    const dog: Animal = {
      name: 'Rex'
    };
    
    const ferrari: Vehicle = {
      model: 'Spider'
    };
    
    console.log(getDesignation<Vehicle>(ferrari)); /// prints Spider
    console.log(getDesignation<Animal>(dog)  /// prints Rex
    
    0 回复  |  直到 5 年前
        1
  •  2
  •   Linda Paiste    5 年前

    正如@kaya3所说,typescript类型只在编译时存在,所以不能对照 interface 在运行时。相反,你需要观察一个对象,看看它是否满足 界面 通过使用类型保护来实现。

    关键词 in 是一个 built-in type guard ,所以你可以这样做:

    const getDesignation = (data: Animal | Vehicle): string => {
        if ('name' in data) {
            return data.name;
        } else {
            return data.model;
        }
    }
    

    事实上,我有点惊讶,因为你可以有一个 Vehicle 具有 {name: number} 但是 seems to work .你可以用一个 XOR 而不是 Animal | Vehicle .

    对于更复杂的用例,您可以创建自己的 user-defined type guards .

    如果它有 string 所有物 name ,我们知道这是一个 Animal :

    const isAnimal = <T extends {}>(value: T & {name?: any}): value is T & Animal => {
        return typeof value.name === "string";
    }
    

    如果它有 一串 所有物 model ,我们知道这是一个 交通工具 :

    const isVehicle = <T extends {}>(value: T & {model?: any}): value is T & Vehicle => {
        return typeof value.model === "string";
    }
    

    您可以使用以下函数来保护变量的类型:

    const getDesignation = (data: Animal | Vehicle): string => {
        if (isAnimal(data)) {
            return data.name;
        } else {
            return data.model;
        }
    }
    

    Playground Link

        2
  •  1
  •   Moritz Vetter    5 年前

    一种稍微不同的方法是为每个要在其上使用此指定逻辑的接口引入一个新接口:

    interface HasDesignation {
        getDesignation: () => string
    }
    
    
    interface Animal extends HasDesignation {
      name: string;
    }
    
    interface Vehicle extends HasDesignation {
      model: string;
    }
    

    现在,您可以构建如下实例:

    const createAnimal = (name: string): Animal => ({
        name,
        getDesignation() { return this.name }
    })
    
    const createVehicle = (model: string): Vehicle => ({
        model,
        getDesignation() { return this.model }
    })
    

    getDesignation 变得非常简单:

    const getDesignation = <T extends HasDesignation>(data: T): string => data.getDesignation()`
    

    Playground

    推荐文章