TypeScript - 通用约束可以提供“允许”类型? [英] TypeScript - can a generic constraint provide "allowed" types?

查看:522
本文介绍了TypeScript - 通用约束可以提供“允许”类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



  type可转换< TKey,TValue> = {[index:TKey]:TValue} 

这会产生以下错误:


索引签名参数类型必须是'string'或'number'。

有没有办法将 TKey 限制为'string'或'number'?

解决方案

正如 @ TitianCernicova-Dragomir 所示,您无法使用 TKey 作为索引签名中的类型,即使它是相当于字符串数字



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

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






Aside :事实证明,在TypeScript中的一堆地方,属性的索引类型必须是 string ,而不是。在这些地方, number 通常被视为 string 的一种子类型。这是因为在JavaScript中,当您使用它们时,索引会转换为 string ,导致这种行为:

  const a = {0:hello}; 
console.log(a [0]); //输出hello
console.log(a ['0'])// * still *输出hello

因为你不能在后面使用 number ,所以我会忽略它;如果您需要使用数字键,TypeScript可能会让您,或者您可以手动转换为字符串。回到答案的其余部分:




如果你想允许 TKey 字符串更具体,这意味着只允许某些键,您可以使用映射类型

  type可转换< TKey extends string,TValue> = {[TKey中的K]:TValue} 

你可以通过传递字符串来使用它或者 TKey 的字符串联合:

  type NumNames ='zero '| 'one'| '二'; 
const nums:可索引< NumNames,number> = {零:0,1:1,2:2};

type NumNumerals ='0'| '1'| 2’ ;
常数:可索引< NumNumerals,number> = {0:0,1:1,2:2};

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

  const anyNums:可索引< string,number> = {uno:1,zwei:2,trois:3}; 






其实这个定义可索引< TKey,TValue> 非常有用,它已经存在于 TypeScript标准库作为记录< K,T>

 键入NumNames ='zero'| 'one'| '二'; 
const nums:记录< NumNames,number> = {零:0,1:1,2:2};

因此,我建议您使用记录< K,T> 用于这些目的,因为它是标准的,其他TypeScript开发人员阅读你的代码更可能熟悉它。






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


Given the following code...

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

This produces the following error:

An index signature parameter type must be 'string' or 'number'.

Is there a way to constrain TKey to be 'string' or 'number'?

解决方案

As @TitianCernicova-Dragomir indicates, you can't use TKey as the type in an index signature, even if it is equivalent to string or number.

If you know that TKey is exactly string or number, you can just use it directly and not specify TKey in your type:

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


Aside: It turns out that in a bunch of places in TypeScript, the index type for properties is required to be a string, and not number. In such places, number is usually treated as a kind of subtype of string. That's because in JavaScript, indices are converted to string anyway when you use them, leading to this kind of behavior:

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

Since you can't use number in what follows, I will ignore it; if you need to use numeric keys TypeScript will probably let you, or you can convert to string manually. Back to the rest of the answer:


If you want to allow TKey to be more specific than string, meaning only certain keys are allowed, you can use mapped types:

type Indexable<TKey extends string, TValue> = { [K in TKey]: TValue }

You'd use it by passing in a string literal or union of string literals for 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};

And if you don't want to limit the key to particular literals or unions of literals, you can still use string as TKey:

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


In fact, this definition for Indexable<TKey, TValue> is so useful, it already exists in the TypeScript standard library as Record<K,T>:

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

I therefore recommend you use Record<K,T> for these purposes, since it is standard and other TypeScript developers who read your code are more likely to be familiar with it.


Hope that helps; good luck!

这篇关于TypeScript - 通用约束可以提供“允许”类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆