【问题标题】:Argument of type 'Barable' is not assignable to parameter of type 'T'“Barable”类型的参数不能分配给“T”类型的参数
【发布时间】:2018-05-08 10:32:30
【问题描述】:

谁能解释一下,为什么这段代码不起作用:

class Fooable {
    foo: string;
}
class Barable extends Fooable { 
    bar: boolean;
}

function simplifiedExample<T extends Fooable>(): Array<T> {
    let list = new Array<T>();
        list.push(new Barable());
    return list;
}

Barable 正在扩展 Fooable。当 T 必须是 Fooable 时,为什么我不能将 Barable 添加到数组中? 这里代码在playground

编辑:

问题是,simplifiedExample() 是基类的覆盖,基类只是一个定义。因为是一个混合项目 JS/TS。

见: new playground

我找到了一个带有演员表的解决方案,但对我来说这似乎不是一个合适的解决方案:

class BarableService extends FooableService { 

    simplifiedExample<T extends Fooable>(): Array<T> { 
        let list = new Array<Fooable>();
            list.push(new Barable());
        return list as Array<T>;
    }
}

【问题讨论】:

    标签: typescript generics inheritance


    【解决方案1】:

    虽然T 类型与Fooable 兼容,Barable 类型与Fooable 兼容,但这并不意味着BarableT 兼容。

    例如:

    class Bazable extends Fooable {
        baz: number;
    }
    
    const result: Bazable[] = simplifiedExample<Bazable>();
    

    这让我想起了一点哲学,因为你可以看到这是不合逻辑的:

    If T (Bazable) is a Fooable
    And Barable is a Fooable
    Then T (Bazable) is a Barable
    

    或者……

    If T (Lion) is a Cat
    And Tiger is a cat
    Then T (Lion) is a Tiger
    
         Cat
         / \
        /   \
    Lion != Tiger
    

    通用 vs 结构

    由于结构类型系统,TypeScript 中有许多情况可以在没有泛型的情况下解决。您可能会发现,对您的 Barable 诚实就可以了:

    function simplifiedExample(): Barable[] {
        let list: Barable[] = [];
        list.push(new Barable());
        return list;
    }
    

    除了兼容的结构之外,你不需要任何东西来通过类型检查:

    class Bazable {
        foo: string;
        bar: boolean;
    }
    
    const a: Bazable[] = simplifiedExample(); 
    

    甚至:

    class Bazable {
        bar: boolean;
    }
    
    const a: Bazable[] = simplifiedExample(); 
    

    当然还有:

    const a: Fooable[] = simplifiedExample();
    

    如果这不符合您的要求,您可能需要提供一个示例,说明您认为需要在何处引入泛型类型。通常,如果您想在函数中构造一个新的T,而不是固定类型。

    【讨论】:

    • 好的,谢谢。 TS 中的泛型不像在 C# 中那样工作。但是这个例子是怎么回事:typescriptlang.org/play/…
    • @razgoolyy 你能看看我关于依赖结构类型的更新是否适用——而不是泛型——适用于你的情况吗?
    • 再次感谢您的帮助。我理解你的建议。但我无法更改该方法的签名。请看我帖子的更新
    【解决方案2】:

    正如@Fenton 指出的TBarable 的兼容性无法在函数中检查。如果需要创建T 的新实例,可以传入构造函数:

    function simplifiedExample<T extends Fooable>(ctor: new ()=> T): Array<T> {
        let list = new Array<T>();
            list.push(new ctor());
        return list;
    }
    
    const result1: Bazable[] = simplifiedExample(Bazable);
    const result2: Barable[] = simplifiedExample(Barable);
    

    【讨论】:

      【解决方案3】:

      你的数组列表的类型是已知的,它应该是Fooable,因此返回类型。

      【讨论】:

      • 这也不起作用。 example
      • 您还应该将返回类型更改为Fooable 的数组,如答案中所述。
      • 我无法更改方法的签名。请看我帖子的更新
      猜你喜欢
      • 2020-08-19
      • 2019-07-27
      • 1970-01-01
      • 2019-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-05
      相关资源
      最近更新 更多