TypeScript类型忽略大小写

mar*_*eto 8 types case-insensitive typescript typescript-typings

我在TypeScript中有这个类型定义:

export type xhrTypes = "GET" | "POST" | "PUT" | "DELETE" | "OPTIONS" | "CONNECT" | "HEAD";
Run Code Online (Sandbox Code Playgroud)

遗憾的是,这是区分大小写的...有没有办法定义它不区分大小写?

谢谢

jca*_*alz 14

TYPESCRIPT 4.1+ 的新答案

欢迎回来!既然 TypeScript 4.1 已经引入了模板字面量类型Uppercase/Lowercase内在字符串映射类型,我们现在可以在不需要正则表达式类型的情况下回答这个问题。


主要有两种方法。“蛮力”方法大量使用递归条件类型和联合,将您xhrTypes变成所有可能的写字符串方式的具体联合,其中大小写无关紧要:

type xhrTypes = "GET" | "POST" | "PUT" | "DELETE" | "OPTIONS" | "CONNECT" | "HEAD";

type AnyCase<T extends string> =
    string extends T ? string :
    T extends `${infer F1}${infer F2}${infer R}` ? (
        `${Uppercase<F1> | Lowercase<F1>}${Uppercase<F2> | Lowercase<F2>}${AnyCase<R>}`
    ) :
    T extends `${infer F}${infer R}` ? `${Uppercase<F> | Lowercase<F>}${AnyCase<R>}` :
    ""


type AnyCaseXhrTypes = AnyCase<xhrTypes>;
Run Code Online (Sandbox Code Playgroud)

如果您检查AnyCaseXhrTypes,您会看到它是一个拥有 368 名成员的工会:

/* type AnyCaseXhrTypes = "GET" | "POST" | "PUT" | "DELETE" | "OPTIONS" | 
"CONNECT" | "HEAD" | "GEt" | "GeT" | "Get" | "gET" | "gEt" | "geT" | "get" | 
"POSt" | "POsT" | "POst" | "PoST" |  "PoSt" | "PosT" | "Post" | 
... 346 more ... | "head" */
Run Code Online (Sandbox Code Playgroud)

然后你可以使用这种类型来代替xhrType你想要不区分大小写的任何地方:

function acceptAnyCaseXhrType(xhrType: AnyCaseXhrTypes) { }

acceptAnyCaseXhrType("get"); // okay
acceptAnyCaseXhrType("DeLeTe"); // okay
acceptAnyCaseXhrType("poot"); // error! "poot" not assignable to big union
Run Code Online (Sandbox Code Playgroud)

蛮力方法的问题在于它不能很好地扩展更多或更长的字符串。TypeScript 中的联合类型限制为 100,000 个成员,并且在编译器抱怨之前,递归条件类型最多只能达到 20 级深度。因此,任何中等长度的单词或中等长度的单词列表都会使上述方法不可行。

type xhrTypes = "GET" | "POST" | "PUT" | "DELETE" | "OPTIONS" | "CONNECT" | "HEAD"
 | "LONG STRINGS MAKE THE COMPILER UNHAPPY";

type AnyCaseXhrTypes = AnyCase<xhrTypes>; // error!
// Type instantiation is excessively deep and possibly infinite.
// Union type is too complex to represent
Run Code Online (Sandbox Code Playgroud)

解决这个问题的一种方法是不再使用特定的具体联合,而是切换到泛型类型表示。如果T是传递给 的字符串值的类型acceptAnyCaseXhrType(),那么我们要做的就是确保它Uppercase<T>可以分配给xhrType。这与其说是一种类型,不如说是一种约束(尽管我们不能直接使用泛型约束来表达这一点):

function acceptAnyCaseXhrTypeGeneric<T extends string>(
    xhrType: Uppercase<T> extends xhrTypes ? T : xhrTypes
) { }

acceptAnyCaseXhrTypeGeneric("get"); // okay
acceptAnyCaseXhrTypeGeneric("DeLeTe"); // okay
acceptAnyCaseXhrTypeGeneric("poot"); // error! "poot" not assignable to xhrTypes
Run Code Online (Sandbox Code Playgroud)

此解决方案要求您将泛型类型参数拉到您可能不需要它们的地方,但它确实可以很好地扩展。


所以,你去!我们所要做的就是等待......(检查笔记)...... 3 年,TypeScript 交付了!

Playground 链接到代码


Rya*_*ugh 9

就这样,这篇文章有一个答案:不,这是不可能的.

更新5/15/2018:仍然不可能.最接近的是,正则表达式验证的字符串类型,在语言设计会议上提出的最近时间并没有被广泛接受.

  • 需要对正则表达式验证的字符串类型提案进行哪些更改才能使其广受欢迎? (2认同)