2017-10-04 153 views
0

通用約束編輯: 固定的「測試」在我無法理解泛型約束是如何在打字稿工作接口打字稿的功能參數

「約束」。

interface SomeConstraint { constraint: any } 
type SomeType<T> = <A extends SomeConstraint>(item: T, action: A) => void; 

正如你所看到的,這是通用的參數和一些約束函數定義:我與反應,和/終極版,你可以找到類似這樣的一個工地打工。現在,當我想使用它,我可以寫出如下:

interface Test { constraint: string } 
const some : SomeType<string> = (s: string, c: Test) => {} 

當我想延長測試接口偉大的工程,但之後,(我們稱之爲TestWithData):

interface TestWithData { constraint: string, payload: any } 
const some : SomeType<string> = (s: string, c: TestWithData) => {} 

我得到一個編譯時錯誤:

錯誤TS2322:類型'(s:string,c:TestWithData)=> void'不能分配給類型'SomeType'。 參數'c'和'action'的類型不兼容。 類型'A'不可分配爲鍵入'TestWithData'。 類型'SomeConstraint'不可分配給'TestWithData'類型。 'SomeConstraint'類型中缺少屬性'test'。

我錯過了什麼?


被修改

正如我說我發現,在終極版分型本(類似)的構建體。當你要定義你減速,你需要提供國家和行動

export type Reducer<S> = <A extends Action>(state: S, action: A) => S; 

現在,我將跳過狀態的一部分,所以,我可以寫:你可以找到這個定義(終極版「3.7.2」)行動是這樣的:

interface MyAction { type: "MY_ACTION" } 

,創造減速很簡單:

const reducer: Reducer<MyState> = (state: MyState, action: MyAction) => {...} 

將通過編譯,但是如果我要MyAction添加額外的數據如下:

interface MyAction { 
    type: "MY_ACTION"; 
    payload: any 
} 

編譯將失敗,出現上述錯誤。我懷疑它會通過。那麼這個約束的目的是什麼?告訴編譯器,我們期望完全相同的類型(結構),沒有更多或更少?我認爲這是一個非常有限的用例,我認爲類型推斷會選擇類型,檢查它的結構兼容性並保留類型簽名。像這樣的,但沒有必要指定類型參數的東西:

export type Reducer<S, A extends Action> = (state: S, action: A) => S; 

現在,類型簽名被保留,但我們需要指定實際的參數類型聲明變量時(如同我們做了狀態):

const reducer: Reducer<MyState, MyAction> = (state: MyState, action: MyAction) => {...} 

回答

1

對於你給的例子,我不認爲通用+約束是我將定義類型的方式(它可能會我會怎麼做,在標稱的類型系統,而不是在一個結構型系統)。

type SomeType<T> = <A extends SomeConstraint>(item: T, action: A) => void; 

如果你說「的項目必須有一個constraint屬性,你可以用得到這個簡單的:

type SomeType<T> = (item: T, action: SomeConstraint) => void; 

結構打字負責其餘的照顧

在實際的。執行時,可以使用任何與SomeType定義兼容的類型...

const actualImplementation: SomeType<string> = (item: string, action: Test): void => { 

} 

下面是完整版本,記住Test接口要麼需要一個constraint屬性,要麼擴展接口,否則你會缺少使類型兼容的基本屬性。

interface SomeConstraint { 
    constraint: any 
} 

type SomeType<T> = (item: T, action: SomeConstraint) => void; 

interface Test extends SomeConstraint{ test: string } 

const actualImplementation: SomeType<string> = (item: string, action: Test): void => { 

} 

const a: Test = { constraint: '', test: '' }; 

actualImplementation('', a); 

上面例子中的關鍵點是,實際的實現可以是你的Test類型沒有錯誤。

+0

謝謝芬頓,我明白你在說什麼,但不幸的是我的例子是錯誤的,我不小心在兩個接口中留下了屬性「測試」的名稱,但它應該被命名爲「約束」。至於爲什麼這樣定義,這是超出我的範圍,這實際上是爲redux輸入類型:導出類型Reducer = (state:S,action:A)=> S; – negyxo

+0

但是除了redux之外,這個構造不應該與以下內容相同: type _SomeType =(item:T,action:A)=> void_? – negyxo