我有一个字符串联合类型,如下所示:
type Suit = 'hearts' | 'diamonds' | 'spades' | 'clubs';
Run Code Online (Sandbox Code Playgroud)
我想要一种类型安全的方法来获取可以在此字符串联合中使用的所有可能值.但由于接口主要是设计时构造,我能做的最好的就是:
export const ALL_SUITS = getAllStringUnionValues<Suit>({
hearts: 0,
diamonds: 0,
spades: 0,
clubs: 0
});
export function getAllStringUnionValues<TStringUnion extends string>(valuesAsKeys: { [K in TStringUnion]: 0 }): TStringUnion[] {
const result = Object.getOwnPropertyNames(valuesAsKeys);
return result as any;
}
Run Code Online (Sandbox Code Playgroud)
这没关系,该函数确保我总是传递一个对象,其中每个键是字符串union中的一个元素,并且每个元素都包含在内,并返回所有元素的字符串数组.因此,如果字符串union更改,则在编译时对此函数的调用将发生错误,如果还未更新的话.
但问题是常量的类型签名ALL_SUITS是('hearts' | 'diamonds' | 'spades' | 'clubs')[].换句话说,TypeScript认为它是一个包含没有或多个这些值的数组,可能带有重复项,而不是只包含所有值的数组,例如['hearts', 'diamonds', 'spades', 'clubs'].
我真正喜欢的是我的泛型getAllStringUnionValues函数指定它返回的方法['hearts', 'diamonds', 'spades', 'clubs'].
我怎样才能做到这一点一般,同时为干越好?
jca*_*alz 48
在应该在2019年3月发布的TypeScript 3.4中,可以通过使用语法告诉编译器将文字元组的类型推断为文字元组,而不是说.这种类型的断言使编译器推断出一个值可能的最窄类型,包括制作所有内容.它应该如下所示:string[]as constreadonly
const ALL_SUITS = ['hearts', 'diamonds', 'spades', 'clubs'] as const; // TS 3.4
type SuitTuple = typeof ALL_SUITS; // readonly ['hearts', 'diamonds', 'spades', 'clubs']
type Suit = SuitTuple[number]; // union type
Run Code Online (Sandbox Code Playgroud)
这将消除对任何类型的辅助功能的需要.祝大家好运!
看起来,从TypeScript 3.0开始,TypeScript可以自动推断元组类型.一旦发布,tuple()您需要的功能可以简洁地写为:
export type Lit = string | number | boolean | undefined | null | void | {};
export const tuple = <T extends Lit[]>(...args: T) => args;
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样使用它:
const ALL_SUITS = tuple('hearts', 'diamonds', 'spades', 'clubs');
type SuitTuple = typeof ALL_SUITS;
type Suit = SuitTuple[number]; // union type
Run Code Online (Sandbox Code Playgroud)
自从我发布这个答案后,如果你愿意为你的库添加一个函数,我找到了一种推断元组类型的方法.退房的功能tuple()在tuple.ts.
export type Lit = string | number | boolean | undefined | null | void | {};
// infers a tuple type for up to twelve values (add more here if you need them)
export function tuple<A extends Lit, B extends Lit, C extends Lit, D extends Lit, E extends Lit, F extends Lit, G extends Lit, H extends Lit, I extends Lit, J extends Lit, K extends Lit, L extends Lit>(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L): [A, B, C, D, E, F, G, H, I, J, K, L];
export function tuple<A extends Lit, B extends Lit, C extends Lit, D extends Lit, E extends Lit, F extends Lit, G extends Lit, H extends Lit, I extends Lit, J extends Lit, K extends Lit>(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K): [A, B, C, D, E, F, G, H, I, J, K];
export function tuple<A extends Lit, B extends Lit, C extends Lit, D extends Lit, E extends Lit, F extends Lit, G extends Lit, H extends Lit, I extends Lit, J extends Lit>(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J): [A, B, C, D, E, F, G, H, I, J];
export function tuple<A extends Lit, B extends Lit, C extends Lit, D extends Lit, E extends Lit, F extends Lit, G extends Lit, H extends Lit, I extends Lit>(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I): [A, B, C, D, E, F, G, H, I];
export function tuple<A extends Lit, B extends Lit, C extends Lit, D extends Lit, E extends Lit, F extends Lit, G extends Lit, H extends Lit>(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H): [A, B, C, D, E, F, G, H];
export function tuple<A extends Lit, B extends Lit, C extends Lit, D extends Lit, E extends Lit, F extends Lit, G extends Lit>(a: A, b: B, c: C, d: D, e: E, f: F, g: G): [A, B, C, D, E, F, G];
export function tuple<A extends Lit, B extends Lit, C extends Lit, D extends Lit, E extends Lit, F extends Lit>(a: A, b: B, c: C, d: D, e: E, f: F): [A, B, C, D, E, F];
export function tuple<A extends Lit, B extends Lit, C extends Lit, D extends Lit, E extends Lit>(a: A, b: B, c: C, d: D, e: E): [A, B, C, D, E];
export function tuple<A extends Lit, B extends Lit, C extends Lit, D extends Lit>(a: A, b: B, c: C, d: D): [A, B, C, D];
export function tuple<A extends Lit, B extends Lit, C extends Lit>(a: A, b: B, c: C): [A, B, C];
export function tuple<A extends Lit, B extends Lit>(a: A, b: B): [A, B];
export function tuple<A extends Lit>(a: A): [A];
export function tuple(...args: any[]): any[] {
return args;
}
Run Code Online (Sandbox Code Playgroud)
使用它,您可以编写以下内容而不是重复:
const ALL_SUITS = tuple('hearts', 'diamonds', 'spades', 'clubs');
type SuitTuple = typeof ALL_SUITS;
type Suit = SuitTuple[number]; // union type
Run Code Online (Sandbox Code Playgroud)
你怎么看?
获得所需内容的最简单方法是明确指定元组类型并从中派生联合,而不是试图强制TypeScript执行反向操作,而不知道该怎么做.例如:
type SuitTuple = ['hearts', 'diamonds', 'spades', 'clubs'];
const ALL_SUITS: SuitTuple = ['hearts', 'diamonds', 'spades', 'clubs']; // extra/missing would warn you
type Suit = SuitTuple[number]; // union type
Run Code Online (Sandbox Code Playgroud)
请注意,您仍然会两次写出文字,一次作为输入SuitTuple,一次作为值ALL_SUITS; 你会发现没有很好的方法可以避免这种方式重复自己,因为当前无法告诉TypeScript 推断元组,它永远不会从元组类型生成运行时数组.
这里的优点是您不需要在运行时对虚拟对象进行密钥枚举.如果你仍然需要它们,你当然可以用西装作为键来构建类型:
const symbols: {[K in Suit]: string} = {
hearts: '?',
diamonds: '?',
spades: '?',
clubs: '?'
}
Run Code Online (Sandbox Code Playgroud)
希望有所帮助.
f v*_*f v 14
轻松而正确地在心里。
字符串联合到字符串数组 - 正确的决定!
type ValueOf<T> = T[keyof T];
type NonEmptyArray<T> = [T, ...T[]]
type MustInclude<T, U extends T[]> = [T] extends [ValueOf<U>] ? U : never;
function stringUnionToArray<T>() {
return <U extends NonEmptyArray<T>>(...elements: MustInclude<T, U>) => elements;
}
/* USAGE */
type Variants = "error" | "success" | "info";
// This is what You want!! :)
let stringArray = stringUnionToArray<Variants>()("error", "success", "info");
Run Code Online (Sandbox Code Playgroud)
TypeScript 3.4附带了更简洁的语法,称为“ const contexts”。它已经合并到master中,因此在PR中应该可以立即使用。
此功能将使通过使用as constor <const>关键字创建不可变(恒定)元组类型/数组成为可能。由于无法修改此数组,因此TypeScript可以安全地采用较窄的文字类型,['a', 'b']而不是较宽的类型,('a' | 'b')[]甚至string[]可以忽略,而我们可以跳过对tuple()函数的调用。
提及你的问题
但是,问题在于常量ALL_SUITS的类型签名为('hearts'|'diamonds'|'spades'|'clubs')[]。 (...宁可这样) ['hearts','diamonds','spades','clubs']
使用新的语法,我们可以准确地实现以下目标:
const ALL_SUITS = <const> ['hearts', 'diamonds', 'spades', 'clubs'];
// or
const ALL_SUITS = ['hearts', 'diamonds', 'spades', 'clubs'] as const;
// type of ALL_SUITS is infererd to ['hearts', 'diamonds', 'spades', 'clubs']
Run Code Online (Sandbox Code Playgroud)
有了这个不可变的数组,我们可以轻松地创建所需的联合类型:
type Suits = typeof ALL_SUITS[number]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8873 次 |
| 最近记录: |