2017-10-12 201 views
1


    class A<T> 
    { 
     some: { [K in keyof T]: (x: T[K]) => T[K] } 
    } 

    interface IB { 
     b: number 
    } 

    class B<T extends IB> extends A<T> 
    { 
     constructor() 
     { 
      super() 

      /** 
      * Type '{ b: (x: T["b"]) => number; }' 
      * is not assignable to type '{ [K in keyof T]: (x: T[K]) => T[K]; }'. 
      */ 
      this.some = { 
       b: x => 2*x 
      } 
     } 
    } 

    interface IC { 
     b: number 
     c: boolean 
    } 

    class C<T extends IC> extends B<T> 
    { 
     constructor() 
     { 
      super() 
      /** 
      * Type '{ b: (x: T["b"]) => number; c: (x: T["c"]) => boolean; }' 
      * is not assignable to type '{ [K in keyof T]: (x: T[K]) => T[K]; }' 
      */ 
      this.some = { 
       b: x => 4*x, 
       c: x => !x 
      } 
     } 
    } 

你好。我尝试在基类“A”中设置通用约束,目的是自动推断派生类中“某些”属性的类型。不幸的是,我不明白为什么我会像上面提到的那样得到TS错误。从我的角度来看,一切似乎都没问题。从打字稿中的基类泛型推断子类属性类型

谢谢!

回答

1

如果我这样做会发生什么?

const b = new B<{ b: 3, z: string }>(); 

正如你所看到的,我通过在类型{ b: 3, z: string },因为它扩展{ b: number }这是可以接受的。这意味着b.some.b应该是(x: 3) => 3。这也意味着b.some.z应该是(x: string) => string类型。 B的实施是真的吗?没有; b.some.b实际上是(x: 3) => number类型,并且b.some.z未定义。所以编译器警告你是有道理的。

首先,让我们照顾z: string问题。也许在A你想要的some属性是可选的,就像这样:

class A<T> 
{ 
    some: {[K in keyof T]?: (x: T[K]) => T[K]} 
} 

这将允许您BC构造函数初始化some,而无需知道额外的属性。

现在,约b: 3。如果你要允许别人来延长number,那么你可以使用的唯一安全的就是身份的功能:

this.some = {}; 
this.some.b = x => x; // okay 

,不过也许你不希望任何人在任何超过number更具体的类型传递的b。不幸的是,没有很好的方法来阻止它。所以,很好,只是文件,用户应该只能通过b可以是任何number类型。在这种情况下,你只是需要告诉编译器不要担心,通过声称thisB<IB>类型:

this.some = {}; 
(this as B<IB>).some.b = x => 2 * x; // okay 

类似的修复可以为您的C类完成。希望有所帮助;祝你好运!

+0

这是一个非常详细的答案:)现在一切都很清楚,你的帮助。非常感谢! – user2340487