我有一個函式 X 接受Record<string, string>:
function X(arg:Record<string, string>) {
...
}
我想定義一個在 T 中通用的函式 Y,它呼叫 X:
function Y<T>(arg:T) {
...
X(arg)
...
}
我想用具有以下字串屬性的介面實體化 T:
interface UserInfo {
name: string;
email: string;
}
Y<UserInfo>({ name: 'Jon', email: '[email protected]' });
但我無法定義Y,因為T不限于Record<string, string>. 如果我寫:
function Y<T extends Record<string, string>>(arg:T) {
...
X(arg)
...
}
然后我不能用UserInfo.
我如何定義 Y?
謝謝!
uj5u.com熱心網友回復:
您遇到了microsoft/TypeScript#15300中報告的情況。該型別Record<string, string>等價于{[k: string]: string}具有字串索引簽名的型別。
TypeScript 將為匿名物件型別(如 type {name: string, email: string})提供隱式索引簽名,以允許您將它們分配給具有索引簽名的型別,只要已知屬性不沖突。但它沒有為結構上等價的interface型別提供隱式索引簽名。這是您可以觀察到介面和匿名物件型別(或此型別別的type別名)之間行為差異的少數幾個地方之一。
microsoft/TypeScript#15300 中給出的理由是,允許匿名物件型別的型別別名的隱式索引簽名比允許介面的隱式索引簽名“更安全”,因為您可以將新成員合并到現有介面中,而您不能這樣做所以對于匿名物件型別。我不確定我是否理解這種推理的動機......但現在,無論如何,這就是 TypeScript 的作業原理。
您的示例代碼的修復方法已經是通用的,將索引簽名約束 T extends Record<string, string>替換為遞回約束 T extends Record<keyof T, string>。我們不能確定它T有一個索引簽名,但我們可以確定它有自己的密鑰:
function Y<T extends Record<keyof T, string>>(arg: T) {
X(arg) // this still works
}
并且該實作有效,因為幸運的是,泛型型別引數T在我們呼叫時允許具有隱式索引簽名X()。
讓我們測驗一下:
interface UserInfo {
name: string;
email: string;
}
Y<UserInfo>({ name: 'Jon', email: '[email protected]' }); // okay
看起來不錯。現在沒有錯誤,因為UserInfo確實可以分配給Record<keyof UserInfo, string>,又名{name: string, email: string}.
Playground 代碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/511212.html
標籤:打字稿仿制药
上一篇:使用泛型的Swift列舉值
下一篇:如何從父抽象類回傳繼承類的實體
