[英]How to define an object of specific functions as a type or an interface?
[英]How to define an object type that does _not_ include a specific member
我正在處理我放入和退出數據庫/動作的對象,有時希望添加和刪除特定於數據庫/動作的字段。
例如,我有:
type EntryEvent<EntryLine> = { type: 'entry' } & EntryLine;
在其他地方,我希望刪除type
成員,以便將EntryEvent<EntryLine>
回EntryLine
。 為此,我使用以下實用程序函數:
export function stripFields<T extends object, K extends keyof T>(
o: T,
fields: K[]
): Omit<T, K> {
const result: Partial<T> = { ...(<object>o) };
for (const field of fields) {
delete result[field];
}
return <Omit<T, K>>result;
}
麻煩的是,生成的對象將不會被識別為EntryLine
。
如果我嘗試將以下內容分配給EntryLine
類型:
stripFields(event, ['type'])
我會得到:
Argument of type 'Pick<EntryEvent<EntryLine>, Exclude<keyof EntryLine, "type">>' is not assignable to parameter of type 'EntryLine'.
'Pick<EntryEvent<EntryLine>, Exclude<keyof EntryLine, "type">>' is assignable to the constraint of type 'EntryLine', but 'EntryLine' could be instantiated with a different subtype of constraint 'Pick<object, never>' ts(2345)
據我所知,這是有道理的,因為如果通用類型EntryLine
包含type
成員,則stripFields
的結果將不再是EntryLine
(因為它將丟失其type
成員)。
有什么方法可以定義約束通用類型EntryLine
以便它不允許帶有type
字段的對象? 還是有其他解決方法?
更新:
以下代碼為我重現了該問題:
type EntryEvent<EntryLine> = { type: "entry" } & EntryLine;
type MyEntryLine = {
a: Date;
};
export function stripFields<T extends object, K extends keyof T>(
o: T,
fields: K[]
): Omit<T, K> {
const result: Partial<T> = { ...(<object>o) };
for (const field of fields) {
delete result[field];
}
return <Omit<T, K>>result;
}
type Callback<EntryLine> = (a: EntryLine) => void;
function thingThatTakesAnEvent<EntryLine>(a: EntryEvent<EntryLine>, callback: Callback<EntryLine>) {
callback(stripFields(a, ["type"]));
}
function thingThatTakesAMyEntryLine(a: MyEntryLine) {
console.log(a.a);
}
declare let event: EntryEvent<MyEntryLine>;
thingThatTakesAnEvent(event, thingThatTakesAMyEntryLine);
“ Pick <EntryEvent <EntryLine>,Exclude <EntryLine的鍵,“類型” >>”可分配給類型“ EntryLine”的約束,但是可以使用約束“ {}”的另一個子類型實例化“ EntryLine”。
這種形式的錯誤消息基本上意味着,您試圖從傳入的泛型類型參數中推斷出太多信息,而泛型類型參數只有調用者/客戶端才能知道。 Typescript不再認為您對它的類型的猜測是安全的。
關於您的代碼,可以將其翻譯為:
function thingThatTakesAnEvent<EntryLine>(
a: EntryEvent<EntryLine>,
callback: Callback<EntryLine>
) {
callback(stripFields(a, ["type"]));
//------ error ------//
}
==> stripFields
的返回類型為Pick< EntryEvent< EntryLine>, Exclude< keyof EntryLine, "type">>
,可以分配給約束EntryLine
(默認為{}
),但是如果調用者調用了該方法像這樣的函數: thingThatTakesAnEvent<{foo: "bar"}>
? 在函數內部,我們不知道它是{foo: "bar"}
,我們應該使用EntryLine
調用callback
,但是我們使用了特定的子類型,這可能與調用者不EntryLine
。
根據目的,您可以執行以下操作:
stripFields
Playground的類型: type Callback<EntryLine> = (a: Omit<EntryEvent<EntryLine>, "type">) => void;
thingThatTakesAndEvent
Playground中進行轉換 : function thingThatTakesAnEvent<EntryLine>(
a: EntryEvent<EntryLine>,
callback: Callback<EntryLine>
) {
callback((stripFields(a, ["type"]) as unknown) as EntryLine);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.