簡體   English   中英

使用打字稿中類型對象的鍵推斷類型

[英]Inferring types with a key of a type object in typescript

所以我有一個類型,我想根據傳遞給函數的鍵值動態更新它的字段。 但是,我想做的方式(brokenFunction)給了我一個分配錯誤:類型“34”不能分配給類型“從不”,類型“34”不能分配給類型“從不”。 workingFunction 有效,但不是那么方便。 有沒有人有辦法使這項工作? 我猜它涉及泛型,但我仍然不明白為什么類型保護不起作用.....

interface Todo {
  id: number;
  text: string;
}

const todo = {
  id: 1,
  text: "Buy milk",
};


function brokenFunction(x: Todo, field: keyof Todo): void {
  if (typeof field === 'number') {
    x[field] = 34
  } else if (typeof field === 'string') {
    x[field] = 'something else'
  }
}


function workingFunction(x: Todo, field: keyof Todo): void {
  if (field == 'id') {
    x[field] = 2345
  } else if (field == 'text') {
    x[field] = 'asdfsf'
  }
}

游樂場鏈接

brokenFunction()field參數的類型是"id" | "text" "id" | "text" ,表示它是字符串"id"或字符串"text" 在這兩種情況下,在運行時, typeof field都是"string" 因此永遠不會到達第一個if塊,而將始終到達第二個:

  if (typeof field === 'number') {
    x[field] = 34; // can never happen
  } else if (typeof field === 'string') {
    x[field] = 'something else'; // might be an error
  }

我想你可能是指這樣的事情,這也不起作用:

function brokenFunction2(x: Todo, field: keyof Todo): void {
  if (typeof x[field] === 'number') {
    x[field] = 34; // error!
  } else if (typeof x[field] === 'string') {
    x[field] = 'something else'; // error!
  }
}

那是因為編譯器不會執行您試圖達到的那種控制流分析; 您希望編譯器根據typeof x[field]縮小field類型,但事實並非如此。 這與一個已知問題 microsoft/TypeScript#10530 相關,其中對屬性的此類括號訪問不會觸發控制流分析縮小。 那好吧。

那么,我們該如何解決呢? 一種可能的方法是創建一個用戶定義的類型保護函數,它明確地告訴編譯器你在尋找什么:

function fieldGuard<T, V>(
  x: T,
  k: keyof T,
  guard: (x: any) => x is V
): k is { [K in keyof T]-?: T[K] extends V ? K : never }[keyof T] {
  return guard(x[k]);
}

函數fieldGuard()接受一個對象x 、該對象k一個鍵,以及一個你想要檢查屬性x[k]的保護函數。 然后根據保護的結果縮小密鑰k的類型。 然后這有效:

function okayFunction(x: Todo, field: keyof Todo): void {
  if (fieldGuard(x, field, (y): y is number => typeof y === 'number')) {
    x[field] = 34;
  } else if (fieldGuard(x, field, (y): y is string => typeof y === 'string')) {
    x[field] = "something else";
  }
}

這有點乏味,但它非常接近您的原始邏輯,並且編譯器願意至少為您做一些檢查。 如果沒有對 microsoft/TypeScript#10530 的修復,我想不出比上面更好的方法,或者只是像在您的workingFunction()檢查鍵本身。

好的,希望有幫助; 祝你好運!

Playground 鏈接到代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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