在打字稿中创建字符串文字联合类型时字符串替换

String replace when creating string literal union type in typescript

我有一个字符串文字联合类型,如下所示:

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

这只是一个示例,因为我的联合类型是一个包含 100 多个案例的列表。

我需要的是一种新类型,其中我将在类型中具有以下“值”:

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

到目前为止,我使用 TypeScript 的 Uppercase 类型来使其大写。

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

这个 returns 是大写联合类型,但是,我仍然在其中使用 - 而不是 _。 有没有办法让我创建一个我可以像这样使用 ${Replace<Uppercase<LowerCaseNames>>} 的类型,以便用 _ 替换 -? 我正在使用 Typescript v4.4.4.

您可以编写一个自定义 Replace<T, S, D> 实用程序类型,它采用字符串 literal type T 并生成一个新版本,其中出现的源字符串 S 被替换为目标字符串 D。这是一种方法:

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}`

这是一个 tail-recursive template literal type,它使用类型参数 A 来累加结果。如果 T 的形式是 L+S+R 一些(可能是空的)“左边部分” L 和一些(可能是空的)“右边part" R,那么你想使用 L as-is,将 S 替换为 D,然后继续对 R。否则,T 不包含 S 而您只想使用 T as-is.


让我们试试看:

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


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

看起来不错!

Playground link to code

这是一个示例,说明我们如何针对单个类型执行此操作

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

参考资料

  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