TypeScript - 通用约束可以提供“允许的”类型吗?

Posted

技术标签:

【中文标题】TypeScript - 通用约束可以提供“允许的”类型吗?【英文标题】:TypeScript - can a generic constraint provide "allowed" types? 【发布时间】:2017-10-23 09:01:57 【问题描述】:

给定以下代码...

type Indexable<TKey, TValue> =  [index: TKey]: TValue 

这会产生以下错误:

索引签名参数类型必须是“字符串”或“数字”。

有没有办法将TKey 限制为“字符串”或“数字”?

【问题讨论】:

【参考方案1】:

正如@TitianCernicova-Dragomir 所指出的,您不能使用TKey 作为索引签名中的类型,即使它是equivalent to string or number

如果您知道TKey 正好是stringnumber,您可以直接使用它而不在您的类型中指定TKey

type StringIndexable<TValue> =  [index: string]: TValue 
type NumberIndexable<TValue> =  [index: number]: TValue 

旁白:TypeScript 将number 视为键类型的string 的一种子类型。这是因为在 javascript 中,当您使用索引时,无论如何都会将其转换为 string,从而导致这种行为:

const a =  0: "hello" ;
console.log(a[0]); // outputs "hello"
console.log(a['0']) // *still* outputs "hello"

编辑:请注意,TS2.9 添加了support for number and even symbol keys in mapped types。我们将使用 keyof any 来表示“您的 TypeScript 版本认为是有效的键类型”。回到答案的其余部分:


如果您想让TKeykeyof any更具体,这意味着只允许某些键,您可以使用mapped types: p>

type Indexable<TKey extends keyof any, TValue> =  [K in TKey]: TValue 

您可以通过为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;

如果您不想将键限制为特定文字或文字联合,您仍然可以将string 用作TKey

const anyNums: Indexable<string, number> =  uno: 1, zwei: 2, trois: 3 ;

其实Indexable&lt;TKey, TValue&gt;的这个定义太有用了,TypeScript standard library as Record&lt;K,T&gt;中已经存在了:

type NumNames = 'zero' | 'one' | 'two';
const nums: Record<NumNames, number> =  zero: 0, one: 1, two: 2 ;

因此,我建议您将 Record&lt;K,T&gt; 用于这些目的,因为它是标准的,并且阅读您的代码的其他 TypeScript 开发人员更有可能熟悉它。


希望有所帮助;祝你好运!

【讨论】:

最佳解决方案:StringIndexableNumberIndexable 正是我最终要做的!非常全面,谢谢。【参考方案2】:

您可以将 TKey 限制为从字符串或数字派生(使用扩展),但这不会满足编译器的要求。 index 必须是数字或字符串,而不是泛型类型或任何其他类型。这记录在language spec

【讨论】:

以上是关于TypeScript - 通用约束可以提供“允许的”类型吗?的主要内容,如果未能解决你的问题,请参考以下文章

具有通用联合约束的 TypeScript 函数返回值

typescript :具有原始类型约束的泛型类型

TypeScript:通过提供类体创建通用匿名类

typescript pouchdb通用数据库提供程序

深入浅出TypeScript- 使用接口和类型别名

TypeScript 3 的通用 curry 函数