在 TypeScript 中创建字符串字面量联合类型时进行字符串替换

6

我有一个字符串文本联合类型,它看起来像这样:

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

这将返回大写的联合类型,但其中仍有 - 而不是 _。 是否有一种方法可以创建一个类型,像这样使用 ${Replace<Uppercase<LowerCaseNames>>},以将 - 替换为 _? 我正在使用 Typescript v4.4.4。

1
有人会认为它会自动将“-”转换为“_”,但显然这是“Uppercase<T>”类型的限制。 - user13258211
4
我的意思是,"-".toUpperCase() 只是 "-",所以我不确定为什么你认为它会变成 "_"。(大写并不等同于在键盘上按下Shift键) - jcalz
2个回答

16
您可以编写一个自定义的Replace<T, S, D>实用程序类型,该类型接受一个字符串字面类型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}`

这是一个使用类型参数 A 累积结果的尾递归模板文字类型。如果 T 的形式为 L+S+R,其中 LR 是一些(可能为空的)“左部分”和“右部分”,那么您希望原样使用 L,用 D 替换 S,然后继续对 R 进行替换。否则,T 不包含 S,您只需要按原样使用 T
让我们来试试:
type LowerCaseNames = 'youku-frame' | 'youku' | 'mini-program' | 'tiktok-frame';


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

看起来不错!

代码的 Playground 链接


2

需要注意的是,对于包含少于或多于单个“-”字符的输入字符串,这可能会产生意外的行为。如果传入“yooku”或“tic-tac-toe”,则分别会得到“unknown”和“TIC_TAC-TOE”。 - jcalz
1
谢谢@jcalz,已更新以适用于“yooku”和“tic-tac-toe”,需要按照您的方式进行操作,您的答案似乎是最佳解决方案。 - Divek John

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接