I was reading the typescript 4.5beta blog post, the author implemented a TrimLeft
utility type to show Tail-Recursion Elimination on Conditional Types
, so I decided to implement a Trim
utility type ( for learning purposes), my question is, what would you and how would you have done it differently?
type Trim<T extends string> =
T extends
`${infer RestOne} ${infer RestTwo}`
? Trim<`${RestOne}${RestTwo}`>
: T extends ` ${infer RestThree} ${infer RestFour}`
? Trim<`${RestThree}${RestFour}`>
: T extends ` ${infer RestFive} ${infer RestSix} `
? Trim<`${RestFive}${RestSix}`>
: T extends `${infer RestSeven} ${infer RestEight} `
? Trim<`${RestSeven}${RestEight}`>
: T;
type TestOne = Trim<" foo"> ; // "foo"
type TestTwo = Trim< " foo "> ; // "foo"
type TestThree = Trim<" foo bar "> ; // "foobar"
type TestThree = Trim<" foo bar "> ; // "foobar"
type TestFour = Trim<"foo bar ">; // "foobar"
basically, it trims out all space in `Trim<T>`
CodePudding user response:
Consider this exmaple:
type Separator = ' ';
type Trim<T extends string, Acc extends string = ''> =
(T extends `${infer Char}${infer Rest}`
? (Char extends Separator
? Trim<Rest, Acc>
: Trim<Rest, `${Acc}${Char}`>)
: (T extends ''
? Acc
: never)
)
type TestOne = Trim<" foo">; // "foo"
type TestTwo = Trim<" foo ">; // "foo"
type TestThree = Trim<" foo bar ">; // "foobar"
type TestThree2 = Trim<" foo bar ">; // "foobar"
type TestFour = Trim<"foo bar ">; // "foobar"
Trim
- iterates through the whole string. If it finds Separator
(empty space) it just omits it and concats Acc
with part of string without separator.