如何基于数组的值定义类型?

时间:2019-02-09 15:59:47

标签: typescript typescript-typings

如果我的类型看起来像数组:

type names = ['Mike', 'Jeff', 'Ben'];

我可以轻松定义另一个类型,该类型在names中具有项的值:

type UserName = names[number]

对于功能:

function hello(name: UserName) {
  console.log(`Hello, ${name}!`)
}

我只能传递MikeJeffBen中的一个来运行hello。如果我提供其他值,例如John,则无法编译。

如果我没有类型 names,但没有 const数组 names怎么办?

const names = ['Mike', 'Jeff', 'Ben'];

type UserName = ???;

function hello(name: UserName) {
  console.log(`Hello, ${name}!`)
}

hello('Mike');

是否可以定义这样的类型UserName

2 个答案:

答案 0 :(得分:3)

TypeScript 3.4, which should be released in March 2019中,可以告诉编译器将字符串文字的元组的类型推断为字符串文字的元组,而不是string[],通过使用as const syntax。它应该看起来像这样:

const names = ['Mike', 'Jeff', 'Ben'] as const; // TS3.4 syntax
type Names = typeof names; // type Names = readonly ['Mike', 'Jeff', 'Ben'] 
type UserName = Names[number]; // 'Mike' | 'Jeff' | 'Ben'

直到那时(在TypeScript 3.0到3.3中),您都可以使用帮助器函数获得此效果,该函数会向编译器提示以推断更窄的类型:

type Narrowable = string | number | boolean | undefined | null | void | {};
const tuple = <T extends Narrowable[]>(...t: T)=> t;
const names = tuple('Mike', 'Jeff', 'Ben');

type Names = typeof names; // type Names = ['Mike', 'Jeff', 'Ben'] 
type UserName = Names[number]; // 'Mike' | 'Jeff' | 'Ben'

(请注意,在两种情况下,您都可以跳过中间的Names类型,只要愿意就可以定义type UserName = (typeof names)[number]

好的,希望能有所帮助。祝你好运!

答案 1 :(得分:1)

同样,大多数情况下应该是:

  1. 声明类型
  2. 将这些类型设置为变量

完全按此顺序。

很少有人会做相反的事情。

但是,如果您确实需要它,可以这样做:

const names = ['Mike', 'Jeff', 'Ben'] as ['Mike', 'Jeff', 'Ben'];

type UserName = typeof names;

因为您想要一个元组类型(['Mike', 'Jeff', 'Ben']),但是默认情况下永远不会将数组推断为元组,而只能将其推断为数组(在这种情况下为string[])。但是,我认为做上述事情没有多大意义,我再次建议您做相反的,惯用的事情:

type UserName = ['Mike', 'Jeff', 'Ben'];
// however the above type is absolutely static 
// and I don't know if it can provide any benefit so maybe this is more correct:
type UserName = ('Mike' | 'Jeff' | 'Ben')[]

const names: UserName = ['Mike', 'Jeff', 'Ben'] // ok