簡體   English   中英

打字稿泛型相關

[英]Typescript generic related

最近進入打字稿世界,看到了與泛型相關的混亂。 我在下面看到了一些代碼。 我知道“Dispatch”之后的 <> 是描述“Dispatch”的類型,但為什么會有 ?

它是否充當描述“動作”中使用的 T 的額外類型信息? 非常感謝

在此處輸入圖片說明

export interface Dispatch<A extends Action = AnyAction> { <T extends A>(action: T): T }

這個聲明是一個調用簽名 等效的聲明是:

export type Dispatch<A extends Action = AnyAction> =
    <T extends A>(action: T) => T

這同樣可以在 TypeScript 文檔中看到: Generic Types

因此,這意味着:

任何類型為Dispatch<A>函數(其中 A 是自由類型變量,其具體類型應擴展Action並默認為AnyAction )接收類型( T )擴展A任何值並返回相同類型的值(可能是它本身) .

類型聲明中的類型參數(此處為A )與函數類型聲明(此處為T )之間的重要區別在於,前者允許您指定函數實現的特定子類型或調用者應期望的子類型,而后者意味着函數應該接受滿足約束的任何類型,調用者可以假設它可以接受任何這樣的類型。

讓我們檢查一下這個界面:

interface Dispatch<A extends Action = AnyAction> {
    <T extends A>(action: T): T;
}

首先,接口DispatchA是通用A ,因此您可以指定A以從中獲取具體類型。 指定的類型A限制為可分配給Action東西,如果您不指定類型,它將默認AnyAction

let actionDispatcher: Dispatch<Action>; //okay
let anyActionDispatcher: Dispatch; // Dispatch<AnyAction>
let badDispatcher: Dispatch<string>; // error!
// not an Action ---------> ~~~~~~

interface FooAction extends Action {
    foo: string;
}

let fooDispatcher: Dispatch<FooAction>; // okay

因此,一旦您指定A ,您就可以通過將A所有實例替換為您指定的類型來獲得具體類型。 讓我們看看Dispatch<FooAction> 你得到這個:

// same type as Dispatch<FooAction>
interface DispatchFooAction {
    <T extends FooAction>(action: T): T;
}

所以,現在的問題是:什么DispatchFooAction

好吧,該接口具有單個調用簽名,因此可以將其用作函數。 讓我們看看簽名: <T extends FooAction>(action: T): T

這是一個泛型函數簽名,其類型參數T必須可分配給FooAction (或在Dispatch<A>指定的任何A ); 它接受一個類型為T的參數並返回一個相同類型的值。


讓我們看看我們是否可以實現和使用Dispatch<FooAction>

// good implementation
fooDispatcher = <T extends FooAction>(a: T) => a; // okay

const x = fooDispatcher({ type: "foo", foo: "" }); // okay, 
// T inferred as { type: string; foo: string; }, x is of that type

const y = fooDispatcher({ type: "foo", foo: "", baz: 1 }); // okay, 
// T inferred as { type: string; foo: string; baz: number; }, y is of that type

const z = fooDispatcher({ type: "foo" }); // error!
// missing foo prop --> ~~~~~~~~~~~~~~~

interface BarAction extends FooAction {
    bar: string;
}

// bad implementation
fooDispatcher = <T extends BarAction>(a: T) => a; // error!
//~~~~~~~~~~~ <-- bar missing in FooAction but required in BarAction

良好的實施工作; fooDispatcher是一個有效的Dispatch<FooAction>因為它是一個函數,它接受FooAction或其任何子類型的輸入,並返回相同的類型。 您可以看到xy正確調用了該函數,但z沒有正確調用,因為輸入不是有效的FooAction

糟糕的實現不起作用; <T extends BarAction>(a: T)=>a只聲稱接受BarAction輸入,但是fooDispatcher需要接受任何FooAction ,並不是每個FooAction都是BarAction


所以,希望這是有道理的,它可以幫助你。 祝你好運!

Playground 鏈接到代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM