下面是我的类型声明:
type Hex = '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f';
// ↓↓ Error: Expression produces a union type that is too complex to represent
type HexColor = `#${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}`;
typescript 版本:5.2.2.
Playground链接:
https://www.typescriptlang.org/play?ts=5.2.2#code/C4TwDgpgBAEhAeUC8UDkAGVAfVBGbqATAQMwEAsBArAQGwEDsBAHAQJwECCBAQgQMIEAIgQCiBAGIEAhgQBGBAMYEAJgQgEAZqgDcAKFCRYCfgHsANqYBOyKAAMAxABIA3nHgBfV+69uEvn29-IM87HSA
感谢@jcalz的回答,我根据他提供的答案做了一个小小的调整,这个Playground链接是最终的结果。
2条答案
按热度按时间wydwbb8l1#
你的类型太复杂了。您正在要求TypeScript验证
22^6
可能性(113,379,904种可能状态)。cbeh67ev2#
TypeScript中没有直接对应于
HexColor
的特定类型。工会类型最多只能容纳大约10万名成员。很少有可能在不遇到这个限制的情况下表示“所有可能组合的联合”。三个Hex
字符的字符串可以表示为联合(223 <11,000),但四个或更多Hex
字符的字符串不能表示为联合(224 > 200,000)。在TypeScript中支持 * 正则表达式验证字符串类型 * 的功能请求由来已久;目前的开放问题是在microsoft/TypeScript#41160。如果实现了这一点,您应该能够以这种方式表示
HexColor
。但是现在这还不是语言的一部分,所以你需要另一种方法。目前,您能得到的最接近的方法是给予特定的
HexColor
类型,而代之以编写一个genericHexColor<T>
类型,它的作用类似于对字符串文字类型输入T
的约束。目标是T extends HexColor<T>
当且仅当T
是有效的HexColor
。此外,如果T
* 不是 * 一个有效的HexColor
,那么HexColor<T>
* 是 * 一个有效的HexColor
,它“接近”T
,这样用户就可以得到一些可破译的错误消息。无论如何,您将使用HexColor<T>
编写一个通用的帮助函数hexColor()
,它只接受有效的十六进制颜色输入,并返回其输入。所以你应该写const y = hexColor("012345")
而不是const y: HexColor = "012345"
。所以一般的方法是这里有一种写
HexColor<T>
的方法,它总是产生一个六个字符的字符串字面量,其字符是来自T
的对应Hex
字符(如果有),否则是"0"
。所以"021GFE"
变成了"0210FE"
(因为"G"
是inavlid),"ABCDE"
变成了"ABCDE0"
(因为字符串太短),"ABCDEFA"
变成了"ABCDEF"
(因为字符串太长):这是一个尾递归条件类型。
L
类型参数是一个累加器,它表示一个元组,该元组的长度与到目前为止处理的字符数相同。A
类型参数是一个累加器,表示到目前为止的累加输出。(理想情况下,我们只使用A
,但你不能直接问TypeScript字符串文字类型有多长,而你可以为元组类型做这件事。所以我用L["length"]
代替A["length"]
。如果
L
是6
,那么我们已经处理了6个字符,我们只返回累积输出A
。否则,我们将T
拆分为第一个字符F
和字符串R
的其余部分(使用模板文字类型和infer
)并递归。下一步使用R
代替T
,一个比L
长一个元素的元组代替L
,对于累积输出,我们在A
上附加一个字符。如果F
是一个有效的Hex
,那么我们附加F
。否则,我们追加"0"
。哦,如果我们不能拆分T
,因为它是空的,那么我们仍然递归,但用一个空字符串""
代替T
,并用"0"
作为附加字符。您可以验证它的行为是否如上所述。
接下来,
hexColor
辅助函数与上面写的略有不同:这是因为你不能写
T extends HexColor<T>
而不得到一个循环错误。因此,我们只需将T
约束为string
,然后将HexColor<T>
应用到h
类型中。同样,写<T extends string>(h: HexColor<T>) => h
是很好的,但这并不能推断h
的字符串文字类型。奇怪的T extends HexColor<T> ? T : HexColor<T>
条件类型具有预期的效果,允许编译器推断T
的字符串文字类型,将其与HexColor<T>
进行比较,然后根据比较成功或失败计算为T
或HexColor<T>
。这是丑陋的/奇怪的,但这是我发现的唯一在实践中有效的方法。好吧,让我们测试一下:
看起来不错。好的调用会成功,而坏的调用会失败,并显示一条错误消息,希望这些信息足以帮助开发人员发现问题。每个错误消息都提到“最接近”的有效输入。对于像
"whatever"
这样完全不好的输入,它可能不是那么明显("00a0e0"
是有效的,并保留了"a"
和"e"
字符,而将其余的替换为"0"
,但谁知道一个困惑的开发人员是否会理解这一点),但希望它足够好。Playground链接到代码