typescript:如何创建一个可以将字符串转换为大写的类型

faw*_*ell 4 typescript typescript-typings

我想在打字稿中创建一个类型,它可以将字符串转换为大写:

type _Upper<T> = ...

_Upper<'abc'> // 'ABC'
Run Code Online (Sandbox Code Playgroud)

谁能告诉我这个吗?

jca*_*alz 7

正确的方法是仅使用现有的Uppercase<T>实用程序类型。这是microsoft/TypeScript#40580intrinsic中引入的类型,这意味着它是在编译器本身中实现的;你可以查看大约第 15,085 行:checker.ts

\n
case IntrinsicTypeKind.Uppercase: return str.toUpperCase()\n
Run Code Online (Sandbox Code Playgroud)\n

_Upper<T>这意味着您可以像这样定义自定义类型:

\n
type _Upper<T extends string> = Uppercase<T>;\n
Run Code Online (Sandbox Code Playgroud)\n

是的,这是一个微不足道的定义。但它的优点是定义简单并且根据Unicode 标准大小写映射算法工作:

\n
type ABC = _Upper<\'abc\'>\n// type ABC = "ABC"\n\ntype Sentence = _Upper<"The quick brown fox jumps over the lazy dog.">;\n// type Sentence = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG."\n\ntype \xd0\xa5\xd0\xbe\xd1\x80\xd0\xbe\xd1\x88\xd0\xbe = Uppercase<"\xd1\x8f \xd0\xbd\xd0\xb5 \xd0\xb7\xd0\xbd\xd0\xb0\xd1\x8e">;\n// type \xd0\xa5\xd0\xbe\xd1\x80\xd0\xbe\xd1\x88\xd0\xbe = "\xd0\xaf \xd0\x9d\xd0\x95 \xd0\x97\xd0\x9d\xd0\x90\xd0\xae"\n
Run Code Online (Sandbox Code Playgroud)\n
\n

如果您不想使用Uppercase<T>,您可以使用递归模板文字类型来自己实现一些东西。但请注意,要准确地做到这一点,您需要保留所有 Unicode 字符的映射,这些字符在转换为大写时需要更改。至少这将是一个相当大的映射(我认为超过 2,000 个字符)。

\n

如果你只关心拉丁字母的 26 个字符,那么你可以这样写:

\n
interface Uppers {\n  a: "A", b: "B", c: "C", d: "D", e: "E", f: "F", g: "G", \n  h: "H", i: "I", j: "J", k: "K", l: "L", m: "M",\n  n: "N", o: "O", p: "P", q: "Q", r: "R", s: "S", t: "T", \n  u: "U", v: "V", w: "W", x: "X", y: "Y", z: "Z"\n}\n\ntype _Upper<T extends string, A extends string = ""> =\n  T extends `${infer F}${infer R}` ?\n  _Upper<R, `${A}${F extends keyof Uppers ? Uppers[F] : F}`> : A;\n
Run Code Online (Sandbox Code Playgroud)\n

Uppers从小写(键)到大写(值)的映射类型也是如此。该_Upper<T>类型逐个字符T地解析字符串。如果字符F是小写 ( F extends keyof Uppers),则将其转换为大写 ( Uppers[F]),否则将其保留(F)。这是一个尾递归定义(使用A类型参数作为累加器),因此在 TypeScript 4.5 及更高版本中,这适用于相当长的字符串文字。

\n

让我们测试一下:

\n
type ABC = _Upper<\'abc\'>\n// type ABC = "ABC"\n\ntype Sentence = _Upper<"The quick brown fox jumps over the lazy dog.">;\n// type Sentence = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG."\n\ntype \xd0\x9f\xd0\xbb\xd0\xbe\xd1\x85\xd0\xbe = _Upper<"\xd1\x8f \xd0\xbd\xd0\xb5 \xd0\xb7\xd0\xbd\xd0\xb0\xd1\x8e">;\n// type \xd0\x9f\xd0\xbb\xd0\xbe\xd1\x85\xd0\xbe = "\xd1\x8f \xd0\xbd\xd0\xb5 \xd0\xb7\xd0\xbd\xd0\xb0\xd1\x8e" // oops\n
Run Code Online (Sandbox Code Playgroud)\n

嗯,前两个都不错。

\n

但最后一个不起作用;小写西里尔字母字符串不受影响。如有必要,可以通过Uppers使用西里尔字母增强类型来解决此问题。这里的基本算法,解析字符串并查找映射中的每个字符,可能是我们能做的最好的算法。嗯,最好的办法是使用内置的Uppercase<T>. 但如果Uppercase<T>不存在,那么像这样的递归条件模板文字类型将是合理的。

\n

Playground 代码链接

\n