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

Time:01-20

Assume inputting a sentence contains one or two spaces and has the structure ${Verb}${one or two spaces}${Activity}, how could I extract the Verb and Activity in Typescript?

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">

I got the result type ["play", "chess"] | ["write", " code" | "code"] | ["read" | "read hacker", "hacker news" | "news"].

Expected: ["play", "chess"] | ["write", "code"] | ["read", "hacker news"].

CodePudding user response:

The reason for the behavior is that S is a union, so any type containing it (such as ${infer Verb}${Split}${infer Activity}) will be considered for both union members. So typescript will then give you both possible results. For "write code" you can split by ' ' and get ["write", " code"] or by ' ' and get ["write", " code"].

You could keep the Split strings in a tuple, and run through them until you get a match using a recursive conditional type:

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

Note that this is a tail recursive type, so the compiler should deal reasonably well with it.

  •  Tags:  
  • Related