Home > Software engineering >  String replace when creating string literal union type in typescript
String replace when creating string literal union type in typescript

Time:03-05

I have a string literal union type that looks like this:

type LowerCaseNames = 'youku-frame' | 'youku' | 'mini-program' | 'tiktok-frame';

This is only an example, since my union type is a list of more than 100 cases.

What I need to have is a new type where I would have the following "values" in type:

type UpperCaseNames = 'YOUKU_FRAME' | 'YOUKU' | 'MINI_PROGRAM' | 'TIKTOK_FRAME';

So far, I am using TypeScript's Uppercase type in order to have it upper-cased.

type UpperCaseNames = `${Uppercase<LowerCaseNames>}`;

What this returns is upper-cased union type but, I still have in them - instead of _. Is there a way for me to create a type that I can use like this ${Replace<Uppercase<LowerCaseNames>>} in order to replace - with _? I am using Typescript v4.4.4.

CodePudding user response:

You can write a custom Replace<T, S, D> utility type which takes a string literal type T and produces a new version where occurrences of a source string S are replaced with a destination string D. Here's one way to do it:

type Replace<T extends string, S extends string, D extends string,
  A extends string = ""> = T extends `${infer L}${S}${infer R}` ?
  Replace<R, S, D, `${A}${L}${D}`> : `${A}${T}`

That's a tail-recursive template literal type which uses a type parameter A to accumulate the result. If T is of the form L S R for some (possibly empty) "left part" L and some (possibly empty) "right part" R, then you want to use L as-is, replace S with D, and then continue doing Replacements on R. Otherwise, T doesn't contain S and you just want to use T as-is.


Let's try it out:

type LowerCaseNames = 'youku-frame' | 'youku' | 'mini-program' | 'tiktok-frame';


type UpperCaseNames = Uppercase<Replace<LowerCaseNames, "-", "_">>
// type UpperCaseNames = "YOUKU" | "YOUKU_FRAME" | "MINI_PROGRAM" | "TIKTOK_FRAME"

Looks good!

Playground link to code

CodePudding user response:

here is an example of how we can do this for a single type

type B = 'youku-frame';
type Replace<S extends string> = S extends `${infer A}-${infer B}`
  ? `${Uppercase<A>}_${Uppercase<B>}`
  : ${Uppercase<B>};

type C = Replace<B>;

References

  1. https://github.com/microsoft/TypeScript/pull/40336
  2. https://github.com/microsoft/TypeScript/pull/40580#issuecomment-731124971
  3. https://devblogs.microsoft.com/typescript/announcing-typescript-4-1-beta/#template-literal-types
  • Related