[英]Typescript Generics: Type argument inference vs Generic default type parameter
我正在努力找出Generic default type parameter
的正確用例。
下面我創建了一個示例,我希望我的泛型 function 使用泛型默認類型參數而不是類型參數推斷。 但是,它似乎不起作用。 我想我無法區分typescript generics這兩個概念。
interface Person<K extends string | number | symbol = string> {
addPerson: (key: K) => void;
}
interface StandardObject {
[key: string]: string;
}
// sometimes I want keys to be string and sometimes string literal
declare function returnPerson<T extends StandardObject = StandardObject>(param: T): Person<keyof T>;
var obj = {
name: "subrato",
gender: "male"
}
const record = returnPerson(obj)
record.addPerson('nam'); // I don't need this error, I want to ignore it
// above line should not throw error but bcz of type argument inference it doesn't
// Why TS uses type argument inference here, why not generic default type parameter `StandardObject`?
const record2 = returnPerson<StandardObject>(obj);
// here TS doesn't yell
// since we explicit define object type argument whose key's would be string
// I don't want to be explicit to ignore the string literal type
record2.addPerson("nam");
const record3 = returnPerson<typeof obj>(obj);
// I want obj key should accept string literal constant only If I have given the type argument like in this record3 example.
record3.addPerson("nam")
一般問題:當 TS 使用 generics 默認類型參數而不是類型參數推斷時?
我的要求是我的通用 function returnPerson
接受 object 其鍵類型有時是字符串,有時是字符串文字。
TL;DR當您使用泛型類型參數作為 function 參數的類型時,類型信息將從該參數的 position 中使用的參數類型推斷出來。
考慮以下示例 - 它與您的問題基本相同,除了它包含您的 function 聲明的實現並且更改了幾個名稱,但是,重要部分是相同的(類型泛型)。
type PersonAdder<K extends PropertyKey = string> = {
addPerson: (key: K) => void;
};
type StringObject = Record<string, string>;
function makePersonAdder <T extends StringObject = StringObject>(param: T): PersonAdder<keyof T> {
// Is the same as no default type parameter because inference always takes place:
// function makePersonAdder <T extends StringObject>(param: T): PersonAdder<keyof T> {
return {
addPerson (key) {
console.log(key);
},
};
};
// Use:
const obj = {
name: "subrato",
gender: "male",
};
const a1 = makePersonAdder(obj); // PersonAdder<"name" | "gender">
a1.addPerson('name'); // ok
a1.addPerson('gender'); // ok
a1.addPerson('nam'); /*
~~~~~
Argument of type '"nam"' is not assignable to parameter of type '"name" | "gender"'.(2345) */
const a2 = makePersonAdder<typeof obj>(obj); // PersonAdder<"name" | "gender"> (identical to a1, original keys are inferred)
a2.addPerson('nam');
// ~~~~~
// same error as with a1
const a3 = makePersonAdder(obj as StringObject); /* PersonAdder<string>
^^^^^^^^^^^^^^^
Use a type assertion so that the inferred keys are simply 'string' */
a3.addPerson('name'); // ok
a3.addPerson('gender'); // ok
a3.addPerson('nam'); // ok
a3.addPerson('any other string'); // ok
a3.addPerson(42); /*
~~
Argument of type 'number' is not assignable to parameter of type 'string'.(2345) */
const a4 = makePersonAdder<StringObject>(obj); // PersonAdder<string> (identical to a3)
a4.addPerson('any other string'); // ok
a4.addPerson(42); /*
~~
Argument of type 'number' is not assignable to parameter of type 'string'.(2345) */
const a5 = makePersonAdder(obj as any); // PersonAdder<string | number | symbol>
a5.addPerson('any other string'); // ok
a5.addPerson(42); // ok
在 function makePersonAdder
中,使用了泛型類型參數T
T
既用作可作為參數param
( extends StringObject
) 的參數提供的內容的約束,又用作用於保存為參數param
提供的參數的推斷類型的變量。 因為返回類型使用從T
( PersonAdder<keyof T>
) 推斷的類型信息,所以在創建返回類型時,參數值的類型總是用於推斷。
在上面的代碼中,有多個示例用法:
a1
從obj
的類型推斷鍵,所以返回類型是PersonAdder<"name" | "gender">
PersonAdder<"name" | "gender">
。
a2
是通過為T
提供精確類型創建的,因此不會根據提供的參數進行推斷。 相反,您提供的參數必須擴展提供的類型。 在這種情況下,它們是相同的類型,所以就像a1
一樣,返回類型是PersonAdder<"name" | "gender">
PersonAdder<"name" | "gender">
(從typeof obj
推斷)。
a3
在提供的參數上使用類型斷言,以便編譯器從斷言類型而不是原始參數的類型推斷。 這導致返回類型為PersonAdder<string>
。
a4
與a2
發生的情況相同,只是這次為T
提供的手動類型是StringObject
,因此返回類型推斷出StringObject
的鍵(它們是string
),從而產生PersonAdder<string>
。
a5
再次使用類型斷言,這次斷言obj
是類型any
。 any
是一種特殊的頂級類型,您可以將其視為本質上允許任何類型信息。 因為這種類型非常廣泛,沒有什么可以限制推理,所以使用所有允許的類型,導致PersonAdder<string | number | symbol>
PersonAdder<string | number | symbol>
PersonAdder<string | number | symbol>
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.