Typescript通用参数比较

时间:2019-10-02 14:42:57

标签: typescript

所以Typescript的generics guide

末尾有这段代码
class BeeKeeper {
    hasMask: boolean = true;
}

class ZooKeeper {
    nametag: string = 'abc';
}

class Animal {
    numLegs: number = 123;
}

class Bee extends Animal {
    keeper: BeeKeeper = new BeeKeeper();
}

class Lion extends Animal {
    keeper: ZooKeeper = new ZooKeeper();
}

function createInstance<A extends Animal>(c: new () => A): A {
    return new c();
}

createInstance(Lion).keeper.nametag;  // typechecks!
createInstance(Bee).keeper.hasMask;   // typechecks!

该程序仅创建一些类,然后定义一个方法来创建给定类的实例。但是,当我们尝试与变量c进行比较时会出现问题。例如,如果我们要检查是否c == Lion,则Typescript会引发错误(playground link)。任何人都知道在进行类型检查的同时还能进行类型检查的方法吗?

4 个答案:

答案 0 :(得分:2)

您可以使用type guards

它看起来像这样:

type Constructor<T extends {} = {}> = new (...args: any[]) => T;

function typeGuard<T>(o: any, className: Constructor<T>): o is T {
  return o === className;
}

function createInstance<A extends Animal>(c: Constructor<A>): A {
    if (typeGuard(c, Lion)) {
        return new c('Lion initialized')
    }
    return new c();
}

还请注意Constructor<A>的用法-您已经提到构造函数将根据类型接收参数-您的实现无法实现,因为构造函数定义未接收任何参数,因此您应该使用Constructor<A>将任意数量的参数传递给构造函数(由您将正确的参数传递给正确的类型构造函数)。

考虑到所有这些因素,我建议使用一种更清洁,更简单的方法。首先定义可以创建的键和对应类型的映射:

type TypeMap = {
    "lion": Lion,
    "bee": Bee
}

然后仅创建工厂函数,该函数将在调用时建议可能的参数(“ lion” |“ bee”),如果输入了未知参数,则显示错误,并解析正确的返回类型。

function createSimpleInstance<T extends keyof TypeMap>(c: T): TypeMap[T] {
    let instance: Animal;
    switch (c) {
        case "lion":
            instance = new Lion("Lion initialized");
            break;
        case "bee":
            instance = new Bee();
            break;
        default:
            throw new Error("Unknown type");
    }
    return instance as TypeMap[T];
}

这样做的最大好处是,您可以在createSimpleInstance中创建LionBee的确切实例,这可以帮助您自动完成每个构造函数所需的确切参数。

请参阅playground

答案 1 :(得分:1)

您可以使用if(c === instanceof Lion)

进行检查

示例:

class BeeKeeper {
    hasMask: boolean = true;
}

class ZooKeeper {
    nametag: string = 'abc';
}

class Animal {
    numLegs: number = 123;
}

class Bee extends Animal {
    keeper: BeeKeeper = new BeeKeeper();
}

class Lion extends Animal {
    keeper: ZooKeeper = new ZooKeeper();
}

function createInstance<A extends Animal>(c: new () => A): A {
    const newInstance = new c();
    if(newInstance instanceof Lion) {
        console.log('Im a Lion');
    }
    return newInstance;
}

createInstance(Lion).keeper.nametag;  // typechecks!
createInstance(Bee).keeper.hasMask;   // typechecks!

希望这能奏效,并祝您愉快:)

答案 2 :(得分:1)

您尝试过以下吗?
if(c instanceof Lion) {

希望我能正确理解您的问题。

答案 3 :(得分:0)

  

我正在寻找一种无需创建类实例的方法。

简单有效:

function createInstance<A extends Animal>(c: new () => A): A {
    const lion: typeof Lion = Lion;
    if (lion.toString() === c.toString()) {
        console.log("Lion detected")
    }
    return new c();
}