【问题标题】:TypeScript Generics: 'type is not assignable to type T'TypeScript 泛型:'类型不可分配给类型 T'
【发布时间】:2018-09-19 20:08:09
【问题描述】:

我已经创建了一个工厂,它将创建某些类的实例。我想使用泛型来确保返回的所有对象都来自扩展抽象类的子类。

我认为下面显示的createInstance 方法的逻辑可以描述为'createInstance() 将返回一个类型T,该类型被限制为扩展Animal 的类。

如您所见,Lion 扩展了 Animal,但我仍然收到编译器警告 type Lion is not assignable to type T

abstract class Animal {
    abstract makeSound(): void;
}

class Bear extends Animal {
    public makeSound() {
        console.log('growl');
    }
}

class Lion extends Animal {
    public makeSound() {
        console.log('roar');
    }
}

function createInstance<T extends Animal>(type: string): T {
    switch(type) {
        case 'bear':
            return new Bear(); // 'type Bear is not assignable to type T'
        case 'lion':
            return new Lion(); // 'type Lion is not assignable to type T'
    }
}

createInstance().makeSound();

我在TypeScript Generics 文档的末尾读到:

在 TypeScript 中使用泛型创建工厂时,有必要 通过构造函数引用类类型。例如,

function create<T>(c: {new(): T; }): T {
    return new c();
}

但如果可能的话,我真的不想将类构造函数传递给函数,并且想了解为什么我首先会收到 not assignable to type T 消息。

谢谢

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    如果你的函数总是返回一个Lion 它的结果类型不是真正的通用。例如,您可以编写 create&lt;Tiger&gt;(),而您的函数仍将返回 Lion。真正的泛型函数会返回一个遵循泛型参数的值。

    正如你所发现的,你可以将构造函数作为参数传递:

    function create<T>(c: {new(): T; }): T {
        return new c();
    }
    

    或者你可以让你的函数不是通用的,并让它返回一个AnimalLion。如果您有基于确定返回类型的参数值的逻辑,则可以有更多的重载:

    // Public signatures, we tie function parameter values to return value for specific types
    function createInstance(type: "Lion"): Lion 
    function createInstance(type: "Tiger"): Tiger 
    // Private signature, not visible from outside
    function createInstance(type: "Lion" | "Tiger"): Animal {
        if(type === "Lion") {
            return new Lion();
        }
        else if(type === "Tiger") {
            return new Tiger(); 
        }
    }
    let tiger = createInstance("Tiger"); // will be typed as Tiger
    let lion = createInstance("Lion");// will be typed as Lion
    let err = createInstance("Lama");// will be an error since the function does not know how to create a Lama
    

    【讨论】:

    • 感谢您的回复。对我来说是个坏例子。我的意思是可以根据开关选择返回的类。让我换个例子。
    • A true generic function would return a value that honors the generic parameter。所以现在我已经更改了我的示例并且在createInstance() 方法中有两个选项,我的类是否不是通用的,因为它总是需要返回一个扩展动物的类?我不希望它简单地返回一个 Animal,因为我可能想使用其他子类特定的方法和属性。相反,我只想知道返回的值 is 是一个 Animal,这样我就可以确定它有一个 makeSound() 方法,但我想要那个实际的子类实例。
    • @Joe 它仍然不是通用的,因为它不适用于任何T,仅适用于从Animal 派生的有限数量的类。您应该考虑重载选项,它正是您要寻找的,它根据参数值返回特定类型的动物。
    • 谢谢提香。这很有帮助
    猜你喜欢
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 2022-11-11
    • 2016-07-31
    • 2020-10-28
    相关资源
    最近更新 更多