網站搜尋

TypeScript 3.5:如何使用索引符號更新物件屬性?


在 TS 3.5 之前,我能做到:

type Nullable<T> = T | undefined;
type KeyOf<T> = Extract<keyof T, string>;
type ExcludeKey<T, K extends KeyOf<T>, E> = T[K] extends Nullable<E> ? never : K;
type ExtractKey<T, K extends KeyOf<T>, E> = T[K] extends Nullable<E>  ? K : never;
type NonFunctionPropertyNames<T> = { [K in KeyOf<T>]: ExcludeKey<T, K, Function>; }[KeyOf<T>];
type TestKey = NonFunctionPropertyNames<Test>;
type TestKeyList = TestKey[];

class Test {
  name!: string;
  age?: number;
  birthDate?: Date;

  resetSomeField(key: TestKey): void {
    this[key] = undefined;    
  }

  resetAllFields(): void {
    const keys = Object.keys(this) as TestKeyList;
    keys.forEach(this.resetSomeField);
  }
}

但是在升級到 3.5.3 之後,這一行

this[key] = undefined;

給我一個錯誤:

錯誤 TS2322:類型 'undefined' 無法指派給類型 'never'。

我知道這種行為現在是有意的,並且是由 3.5 版本中引入的破壞性更改之一引起的:https://github.com/microsoft/TypeScript/wiki/Breaking-Changes#fixes-to-unsound-writes-to-indexed-access-types

但其中提到的變通方法對我不起作用——因為我有數百個不同類型屬性的對象。而且我也不想像那裡建議的那樣,為每組相同類型的屬性引入單獨的重置函數。

我也無法找到一個編譯器選項來啟用這個新行為。

我可以選擇使用之前的 TS 版本。但這顯然只是暫時的解決方案。

那有人能建議一個解決方法嗎?

答案#1

問題在於你的 name! 欄位是必填的(由非空斷言運算子 ! 所要求)。如果你將它改成 ?,則 Typescript 的錯誤就會消失。

之前:

之後:

class Test {
  name?: string;
  age?: number;
  birthDate?: Date;

  resetSomeField(this: Test, key: TestKey): void {
    this[key] = undefined
  }
...

在這裡玩它

答案#2

從技術層面來看這或許是錯誤的做法,但它實在太麻煩了,所以我還是採用了它:

 (object[key] as any) = newVal;