2017-10-12 79 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