簡體   English   中英

如何在 TypeScript 中正確鍵入和轉換泛型?

[英]How to correctly type and cast a generic in TypeScript?

我不知道如何正確提問,因為我不明白 TypeScript 中的類型如何與泛型一起工作,但我知道如何解釋它,例如,假設我有一個“函數存儲”:

const functionStore: Array <Function> = [];

我有一個函數可以將函數添加到函數存儲中,該函數允許接收一個對象並指定將添加到通過參數傳遞的對象的函數的鍵的名稱:

const addFunction = <Obj = { [index: string]: any }>(
    obj: Obj,
    ...extractFunction: Array<keyof Obj>
) => {
    for (const key of extractFunction) {
        functionStore.push(obj[key]);
    }
};

因此,如果我創建以下對象並將其傳遞給addFunction

const obj = {
    msg: 'Welcome!',
    test() {
        console.log('Hello!!');
    },
    doNoAdd() {
        console.log('Do not add!');
    },
    otherTest() {
        console.log('Other test!!');
    }
};

addFunction(obj, 'test', 'otherTest');

這不起作用,因為“類型' Obj[keyof Obj] '的參數不能分配給' Function '類型的參數”:

...
for (const key of extractFunction) {
    functionStore.push(obj[key]); //<-- Error!!
}
...

如果我進行轉換,它仍然會給出錯誤,因為它是泛型的,該屬性可以是stringnumberarray等(我認為可能有更好的選擇,而不是轉換為unknownany first ):

...
functionStore.push(obj[key] as Function); //<-- Conversion of type 'Obj[keyof Obj]' to type 
                                          //     'Function' may be a mistake because neither
                                          //     type sufficiently overlaps with the other. 
                                          //     If this was intentional, convert the
                                          //      expression to 'unknown' first.
...

我如何進行打字,其中指定了這些鍵,除了作為obj的鍵之外,我還可以指定它引用對象obj的函數?

我希望你可以幫助我 :)

為了使它更安全一些,您可以向Obj添加更多約束。

type Fn = (...args: any[]) => any

const functionStore: Array<Fn> = [];


type ExtractFn<T> = {
    [Prop in keyof T]: T[Prop] extends Fn ? Prop : never
}[keyof T]

const addFunction = <Obj extends Record<string, any>>(
    obj: Obj,
    ...extractFunction: Array<ExtractFn<Obj>>
) => {
    for (const key of extractFunction) {
        functionStore.push(obj[key]);
    }
};
const obj = { name: 'John', getName: () => 'John' }

addFunction(obj, 'getName') // ok
addFunction(obj, 'name') // expected error

Playground您可能已經注意到,您不能提供與功能不對應的鍵。

問題在於泛型的定義方式, =運算符分配了一個默認類型,這可能永遠不會發生,因為它總是由TS從類型Obj的參數推斷出來。 在這里修復它的是使用extend運算符,該運算符將約束參數以擴展提供的接口。

像這樣:

// this is pretty cool
const functionStore: Array <Function> = [];

// so it should extend the interface that you have defined
const addFunction = <Obj extends { [index: string]: any }>(
    obj: Obj,
    ...extractFunction: Array<keyof Obj>
) => {
    for (const key of extractFunction) {
        functionStore.push(obj[key]);
    }
};

應該這樣做 - 操場


補充一點,如果您查看 Playground 鏈接並將鼠標懸停在addFunction調用上,您會注意到泛型類型是由您提供的參數推斷出來的。 這是關於Generic Constraints的文檔。

暫無
暫無

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

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