我经常使用代码如
export type Stuff = 'something' | 'else'
export const AVAILABLE_STUFF: Stuff[] = ['something', 'else']
这样我就可以使用Stuff
类型,并在需要时迭代所有可用的东西。
这有效,但感觉就像重复两次信息。而你必须要小心,因为更新Stuff
或AVAILABLE_STUFF
也需要更新其对应物。
有没有更好的方法从Array定义类型,甚至有点使用数组键入一些数据?
一个内置选项是使用枚举而不是类型和数组方法。
export enum Stuff {
something = 'something',
else = 'else',
}
export const AVAILABLE_STUFF: Stuff[] = Object.values(Stuff);
另一种选择是从AVAILABLE_STUFF
的类型中提取类型。为此,我们必须强制编译器为AVAILABLE_STUFF
推断字符串文字的元组。这可以使用3.4
在as const
中完成,或者在使用额外功能的3.4
之前完成。在AVAILABLE_STUFF
是元组类型后,我们可以使用类型查询来获取元素的类型:
export const AVAILABLE_STUFF = (<T extends string[]>(...o: T)=> o)('something', 'else'); // typed as ["something", "else"]
// export const AVAILABLE_STUFF = ['something', 'else'] as const; // typed as ["something", "else"] in 3.4
export type Stuff = typeof AVAILABLE_STUFF[number] //"something" | "else"
以上代码的一些解释。 typeof AVAILABLE_STUFF
为我们提供了常量(["something", "else"]
)的类型,以使[number]
被称为type query,它将为我们提供元组中项目的类型。
(<T extends string[]>(...o: T)=> o)
只是我们用来强制编译器推断字符串文字元组类型的IIFE。它必须是通用的,因为编译器只会在某些情况下推断文字类型和元组(一个约束为string
的类型参数就是其中之一)。 as const
版本是我推荐使用的版本,因为它更具可读性。
另一种可能性是创建一个对象并使用keyof
。我推荐这种方式只有你有任何有用的东西存储为值(在下面的代码中代替null
)。
const stuffDict = {
something: null,
else: null,
}
type Stuff = keyof typeof stuffDict
const AVAILABLE_STUFF = Object.keys(stuffDict) as Stuff[]