我正在努力找出正確的用例Generic default type parameter。
下面我創建了一個示例,我希望我的泛型函式使用泛型默認型別引數而不是型別引數推斷。但是,它似乎不起作用。我想我無法區分打字稿泛型的兩個概念。
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 使用泛型默認型別引數而不是型別引數推斷時?
我的要求是我的通用函式returnPerson接受一個物件,其鍵型別有時是字串,有時是字串文字。
uj5u.com熱心網友回復:
TL;DR當您使用泛型型別引數作為函式引數的型別時,型別資訊將從在該引數位置使用的引數的型別中推斷出來。
考慮以下示例 - 它與您的問題基本相同,除了它包含函式宣告的實作并且更改了幾個名稱,但是重要部分是相同的(型別泛型)。
TS游樂場
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
在函式makePersonAdder中,使用了泛型型別引數T。
T既可用作引數param( extends StringObject) 的實參的約束條件,又可用作保存為 parameter 提供的實參的推斷型別的變數param。因為回傳型別使用從T( PersonAdder<keyof T>) 推斷的型別資訊,所以在創建回傳型別時總是在推斷中使用引數值的型別。
在上面的代碼中,有多個示例用法:
a1從 的型別推斷鍵obj,因此回傳型別為PersonAdder<"name" | "gender">.a2is created by supplying an exact type forT, so that no inference takes place from the argument provided. Instead, the argument that you provide must extend the type provided. In this case, they are the same type, so just like witha1, the return type isPersonAdder<"name" | "gender">(inferred fromtypeof obj).a3uses a type assertion on the argument provided, so that the compiler infers from the asserted type rather than original parameter's type. This results in the return type beingPersonAdder<string>.a4is the same scenario as what's happening witha2, except that the manual type supplied forTisStringObjectthis time, so the return type infers the keys ofStringObject(which arestring), resulting inPersonAdder<string>.a5uses a type assertion again, this time asserting thatobjis typeany.anyis a special top type which you can think of as essentially allowing any type information. Because this type is so broad, there's nothing to restrict the inference, so all of the permissible types are used, resulting inPersonAdder<string | number | symbol>.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/439047.html
