簡體   English   中英

如何定義不包含特定成員的對象類型

[英]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

根據目的,您可以執行以下操作:

  1. 更改您的回調類型以匹配stripFields Playground的類型:
type Callback<EntryLine> = (a: Omit<EntryEvent<EntryLine>, "type">) => void;
  1. 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.

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