在 Typescript Template Literal 中使用 infer 关键字从句子中提取特定部分?

Extract specific parts from sentence by using infer keyword in Typescript Template Literal?

假设输入一个句子包含一个或两个空格并且具有${Verb}${one or two spaces}${Activity}结构,我如何提取Typescript中的VerbActivity

type Split = ' ' | '  '

type ExtractVerb<S extends string> =
    S extends `${infer Verb}${Split}${infer Activity}`
    ? [Verb, Activity]
    : never;

type Verbs = ExtractVerb<"play chess" | "write  code" | "read hacker  news">

我得到了结果类型["play", "chess"] | ["write", " code" | "code"] | ["read" | "read hacker", "hacker news" | "news"]

预计:["play", "chess"] | ["write", "code"] | ["read", "hacker news"]

该行为的原因是 S 是一个联合,因此任何包含它的类型(例如 ${infer Verb}${Split}${infer Activity})都将被视为两个联合成员。所以打字稿会给你两种可能的结果。对于 "write code",您可以按 ' ' 拆分并得到 ["write"" code"] 或按 ' ' 拆分并得到 ["write"" code"].

您可以将 Split 字符串保存在一个元组中,并 运行 通过它们直到您使用递归条件类型获得匹配:

type Split = ['  ', ' ']

type ExtractVerb<S extends string, Seprators extends string[] = Split> =
    Seprators extends [infer FirstSeparator, ...infer RestSeparators] ?
        S extends `${infer Verb}${FirstSeparator & string}${infer Activity}`
            ? [Verb, Activity]
            : ExtractVerb<S, RestSeparators & string[]>
        : never

type Verbs = ExtractVerb<"play chess" | "write  code" | "read hacker  news">

Playground Link

请注意,这是一个 tail recursive type,因此编译器应该可以很好地处理它。