網站搜尋

在 TypeScript 中,泛型被一般化為字串


我有一個通用函數,可以簡化為下面的範例:

type Delegate<Key extends "firstKey" | "secondKey"> = {
  key: Key;
  deleteMany: (where: { where: { [n in Key]: string } }) => Promise<unknown>;
};

const removeDuplicatesGeneric = <Key extends "firstKey" | "secondKey">(
  delegate: Delegate<Key>
) => {
  delegate.deleteMany({ where: { [delegate.key]: 'key' } });
};

由於 key 屬於 Key,我預期它在傳遞到哪裡時不會造成問題。不過 TypeScript 顯示一個錯誤:

Type '{ [x: string]: string; }' is not assignable to type '{ [n in Key]: string; }'.

有人知道為什麼 [delegate.key] 會被解讀為 x: string 而不是 x: Key 嗎?

答案#1

這種行為是設計使然。由於 string 類型比 "firstKey" | "secondKey" 廣泛得多,因此你會遇到錯誤。

在這種情況下,使用類型斷言是可以的:

type Delegate<Key extends "firstKey" | "secondKey"> = {
    key: Key;
    deleteMany: (arg: { where: Record<Key, string> }) => Promise<unknown>;
};

const record = <
    Key extends PropertyKey,
    Value
>(key: Key, value: Value) =>
    ({ [key]: value }) as Record<Key, Value>

const removeDuplicatesGeneric = <Key extends "firstKey" | "secondKey">(
    delegate: Delegate<Key>
) => {
    delegate.deleteMany({ where: record(delegate.key, 'key') });
};

遊樂場