通用扩展类

时间:2017-07-16 02:14:14

标签: typescript

此TypeScript代码:

class Foo {}

function bar<T extends Foo>(): void {
  let value: T = new Foo();
}

给出了这个错误:

foo.ts(4,7): error TS2322: Type 'Foo' is not assignable to type 'T'.

这似乎对我不对:TFoo延伸,因此Foo应该与T兼容

为什么会发生此错误?

作为使用T extends Foo某些情况下正常工作的证据,这是另一个不会出现类型错误的示例:

class Foo {
  protected _foo: number;

  getFoo(): number {
    return this._foo;
  }
}

class Bar extends Foo {
  protected _bar: number;
}

function bar<T extends Foo>(a: T) {
  return a.getFoo();
}

bar(new Foo());
bar(new Bar());

请注意,bar函数无法访问Bar上的任何属性,它只能访问Foo上的属性,这正是我所期望的。

另请注意,我们可以将类型Foo的值分配给T,但只能通过传入Foo作为参数,而不是使用let a: T = new Foo() }

上面的代码是我更大的应用程序的一个非常小的简化测试用例。我想这样做:

class Foo {
    // Various properties and methods
    protected _foo: number;
}


class Bar extends Foo {
    // Various properties and methods
    protected _bar: number;
}


class Qux<T extends Foo> {
    // Various properties and methods which work on Array<T>
    protected _list: Array<T>;

    get list(): Array<T> {
        // Do initialization / caching / etc.
        return this._list;
    }
}


class Corge<T extends Bar> extends Qux<T> {
    constructor() {
        super();
        this._list = [new Bar()];
        let value: Array<Bar> = this.list;
    }
}

这允许我将通用方法放入Qux Array<Foo>,这些方法也适用于Corge,即使Corge使用Array<Bar> }

但由于类型错误,这不起作用。

2 个答案:

答案 0 :(得分:2)

T扩展Foo,这意味着类型T的值可分配给Foo类型的变量。不是相反。

使用更具体的例子,假设你有:

class FooPlus extends Foo {
    public fooPlusMethod() { }
}

function test<T extends Foo>() {
    let x: T = new Foo();
}

test<FooPlus>();

在这种情况下,函数中的变量x应该具有类型FooPlus,因此您应该能够调用x.fooPlusMethod(),但是您要为其分配一个新实例是Foo的,没有那种方法。

以下是基于您自己的代码的相同示例:

let x = new Corge<BarPlus>();

现在,当我调用x.list时,我希望它返回Array<BarPlus>,因为它扩展了Qux<BarPlus>实现了该方法,但我将返回一个包含一个数组的数组Bar类型的元素,它没有实现我期望从BarPlus获得的所有功能。

答案 1 :(得分:0)

T可能会有其他成员,因此您可以将类型T的值分配给Foo类型的变量,但不能相反。

这里的例子:

type Foo = { a: number };
type Bar = { a: number, b: string };

let foo: Foo = { a: 1 };
let bar: Bar = { a: 1, b: '1' };

foo = bar; // OK
bar = foo; // error: "Property 'b' is missing in type 'Foo'"

也许是一个更简单的例子:

class Shape {
    type: string
}

class Square extends Shape {
    width: number;
}

let shape: Shape = new Square(); //OK
let square: Square = new Shape(); //error - that's what you're trying to do