ser*_*0ne 9 generics generic-constraints typescript
鉴于以下代码......
type Indexable<TKey, TValue> = { [index: TKey]: TValue }
Run Code Online (Sandbox Code Playgroud)
这会产生以下错误:
索引签名参数类型必须是"字符串"或"数字".
有没有办法约束TKey为'字符串'或'数字'?
就像@ TitianCernicova-Dragomir指出的TKey那样,即使它等于string或number也不能用作索引签名中的类型。
如果您知道TKey确切地是string或number,则可以直接使用它,而无需TKey在您的类型中指定:
type StringIndexable<TValue> = { [index: string]: TValue }
type NumberIndexable<TValue> = { [index: number]: TValue }
Run Code Online (Sandbox Code Playgroud)
旁白:事实证明,在TypeScript的许多地方,属性的索引类型必须是string,而不是number。在这些地方,number通常被视为一种亚型的string。这是因为在JavaScript中,无论string何时使用索引,索引都将转换为索引,从而导致这种行为:
const a = { 0: "hello" };
console.log(a[0]); // outputs "hello"
console.log(a['0']) // *still* outputs "hello"
Run Code Online (Sandbox Code Playgroud)
由于您不能number在随后的内容中使用,因此我将忽略它;如果您需要使用数字键,TypeScript可能会让您使用,也可以string手动转换为。返回其余的答案:
如果你想允许TKey以更具体的比string,这意味着只有某些键被允许,您可以使用映射的类型:
type Indexable<TKey extends string, TValue> = { [K in TKey]: TValue }
Run Code Online (Sandbox Code Playgroud)
您可以通过传入以下字符串文字或字符串文字并集来使用它TKey:
type NumNames = 'zero' | 'one' | 'two';
const nums: Indexable<NumNames, number> = { zero: 0, one: 1, two: 2 };
type NumNumerals = '0' | '1' | '2';
const numerals: Indexable<NumNumerals, number> = {0: 0, 1: 1, 2: 2};
Run Code Online (Sandbox Code Playgroud)
如果你不希望限制的关键,尤其是文字或文字的工会,你仍然可以使用string如TKey:
const anyNums: Indexable<string, number> = { uno: 1, zwei: 2, trois: 3 };
Run Code Online (Sandbox Code Playgroud)
实际上,这个定义Indexable<TKey, TValue>非常有用,它已经存在于TypeScript标准库中,如下所示Record<K,T>:
type NumNames = 'zero' | 'one' | 'two';
const nums: Record<NumNames, number> = { zero: 0, one: 1, two: 2 };
Run Code Online (Sandbox Code Playgroud)
因此,我建议您将它们Record<K,T>用于这些目的,因为它是标准的,并且其他阅读您的代码的TypeScript开发人员更可能熟悉它。
希望能有所帮助;祝好运!