定义逗号分隔联合类型的 Typescript 字符串类型?

Ari*_*Ari 14 typescript

如何创建 Typescript 字符串类型,其中包含联合类型中的值并且以逗号分隔?

我认为这个不存在,但我还是想问......

type AcceptableVal = 'cool' | 'wow' | 'biz' | 'sweet' | 'yowza' | 'fantastic';
type Amaze = // how do you define this?;

const dabes: Amaze = 'cool,wow';
const fancy: Amaze = 'biz,wow,fantastic';
const hachiMachi: Amaze = 'yowza,biz,sweet';
Run Code Online (Sandbox Code Playgroud)

Ale*_*yne 16

打字稿 4.3.4 更新

您现在可以使用字符串模板文字类型来定义模式,例如:

type S = 'cool' | 'wow' | 'biz' | 'sweet' | 'yowza' | 'fantastic';
type Test = `${S},${S}`
Run Code Online (Sandbox Code Playgroud)

您仍然无法做的是使其可以像数组一样无限扩展。为了完成这项工作,打字稿将每个组合生成为一个联合。但对于像这样的小列表,它可以工作。

例如:

type S = 'cool' | 'wow' | 'biz' | 'sweet' | 'yowza' | 'fantastic';
type Amaze =
    | `${S}`
    | `${S},${S}`
    | `${S},${S},${S}`
    | `${S},${S},${S},${S}`
    | `${S},${S},${S},${S},${S}`
    | `${S},${S},${S},${S},${S},${S}`
Run Code Online (Sandbox Code Playgroud)

如果将鼠标悬停在 上Amaze,您将看到报告的类型:

type Amaze = S | "cool,cool" | "cool,wow" | "cool,biz" | "cool,sweet" 
| "cool,yowza" | "cool,fantastic" | "wow,cool" | "wow,wow"
| "wow,biz" | "wow,sweet" | "wow,yowza" | "wow,fantastic"
| ... 55967 more ...| "fantastic,fantastic,fantastic,fantastic,fantastic,fantastic"
Run Code Online (Sandbox Code Playgroud)

查看打字稿游乐场

请注意... 55967 more ...Amaze 现在是一个具有超过五万五千个可能值的联合。此时这可能会影响 IDE 的性能。如果您添加需要 7 个字符串的版本,您将收到类型错误:

Expression produces a union type that is too complex to represent.(2590)
Run Code Online (Sandbox Code Playgroud)

最终,打字稿会因为性能原因而切断你的支持。但同样,对于小列表,这可能是可行的。


原始答案:Typescript 3.7

你不能。

Typescript 可以输入string可以包含任何内容的 s,也可以输入精确的字符串,例如"cool""wow"。但打字稿永远不会知道字符串是否包含某些字符。

实现此目的的唯一方法是将它们存储为数组:

type AmazeArray = AcceptableVal[];
const dabes: AmazeArray = ['cool', 'wow'];
Run Code Online (Sandbox Code Playgroud)


MHA*_*A15 8

使用 ts4.1 的新模板字符串功能,您可以使用以下实用程序来执行此操作

type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void
    ? I
    : never;
type UnionToOvlds<U> = UnionToIntersection<U extends any ? (f: U) => void : never>;

type PopUnion<U> = UnionToOvlds<U> extends (a: infer A) => void ? A : never;

type UnionConcat<U extends string, Sep extends string> = PopUnion<U> extends infer SELF
    ? SELF extends string
        ? Exclude<U, SELF> extends never
            ? SELF
            :
                  | `${UnionConcat<Exclude<U, SELF>, Sep>}${Sep}${SELF}`
                  | UnionConcat<Exclude<U, SELF>, Sep>
                  | SELF
        : never
    : never;
Run Code Online (Sandbox Code Playgroud)

例子

type Keys = "a" | "b" | "c";
type Test = UnionConcat<Keys, ",">
// Test = "a" | "b" | "c" | "a,b" | "a,c" | "b,c" | "a,b,c"


type Test2 = UnionConcat<Keys, "-">
// Test2 = "a" | "b" | "c" | "a-b" | "a-c" | "b-c" | "a-b-c"

Run Code Online (Sandbox Code Playgroud)