是否可以编写一个实用程序类型Number<T>,它接受可以转换为数字的字符串文字类型,如果不能,则返回一个never类型?
type Five = Number<'5'> // `Five` is of the type number 5
Run Code Online (Sandbox Code Playgroud)
我只是想先回答一下我为什么要这样做的问题:
我问这个问题的原因是我正在尝试编写一个Add实用程序类型来添加数字
type createArray<Len, Ele, Arr extends Ele[] = []> = Arr['length'] extends Len ? Arr : createArray<Len, Ele, [Ele, ...Arr]>
type Add<A extends number, B extends number> = [...createArray<A, 1>, ...createArray<B, 1>]['length']
Run Code Online (Sandbox Code Playgroud)
现在它有效
type Five = Number<'5'> // `Five` is of the type number 5
Run Code Online (Sandbox Code Playgroud)
但它只接受number类型。我想让它也不接受string类型,这样它也可以工作type Answer = Add<'3','10'>
Tob*_* S. 13
TypeScript 4.8 将允许将字符串文字类型转换为其他类型,例如number,bigint或boolean。请参阅此公关。
通过创建实用程序类型,ParseInt我们可以将字符串文字“转换”number为类型。
type ParseInt<T> = T extends `${infer N extends number}` ? N : never
type T0 = ParseInt<"1"> // 1
type T1 = ParseInt<"100"> // 100
type T2 = ParseInt<"-13"> // -13
type T3 = ParseInt<"abc"> // never
Run Code Online (Sandbox Code Playgroud)
以下是其他类型转换的示例:
type ParseBigint<T> = T extends `${infer N extends bigint}` ? N : never
type T4 = ParseBigint<"1"> // 1n
type T5 = ParseBigint<"100"> // 100n
type T6 = ParseBigint<"abc"> // never
type ParseBoolean<T> = T extends `${infer N extends boolean}` ? N : never
type T7 = ParseBoolean<"true"> // true
type T8 = ParseBoolean<"false"> // false
type T9 = ParseBoolean<"abc"> // never
Run Code Online (Sandbox Code Playgroud)
不,没有办法将任意字符串文字类型转换为数字文字类型(我通常称之为StringToNumber<T>)。最近在microsoft/TypeScript#47141上提出了一个请求,但遭到拒绝。这不是他们愿意支持的事情。microsoft/TypeScript#26382上有一个仍然悬而未决的问题,要求支持文字类型的任意数学,其中包括要求StringToNumber<T>; 也许还有一些希望?但我不会指望它。
如果您关心的只是小于 1000 左右的非负整数(由于即使使用尾部调用消除,递归也受到限制),那么您可以通过元组操作自行实现它,类似于您的做法Add:
type StringToNumber<T extends string, A extends any[] = []> =
T extends keyof [0, ...A] ? A['length'] : StringToNumber<T, [0, ...A]>
Run Code Online (Sandbox Code Playgroud)
你可以看到它的工作原理:
type Thirteen = StringToNumber<"13">;
// type Thirteen = 13
Run Code Online (Sandbox Code Playgroud)
这是脆弱的,就像Add......如果你传递了意想不到的东西,你可能会得到编译器性能缓慢或错误:
// type Nope = Add<0.4, 10>
// Type instantiation is excessively deep and possibly infinite.(2589)
Run Code Online (Sandbox Code Playgroud)
因此,您可以尝试将输入限制为有效的数字字符串:
type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "";
type NonZero = Exclude<Digit, "0" | "">
type LessThanAThousand = "0" | `${NonZero}${Digit}${Digit}`
type StringToNumber<T extends LessThanAThousand, A extends any[] = []> =
T extends LessThanAThousand ? T extends keyof [0, ...A] ?
A['length'] : StringToNumber<T, [0, ...A]> : never;
type Oops = StringToNumber<"0.4"> // error
// ----------------------> ~~~~~
// Type '"0.4"' does not satisfy the constraint 'LessThanAThousand'.(2344)
Run Code Online (Sandbox Code Playgroud)
这样就可以了。
但我仍然不知道我会推荐这样的东西,除非有一个非常好的用例。TS 团队认为实用Add程序类型本身并不值得支持(这可能就是 ms/TS#47141 被拒绝的原因)。
| 归档时间: |
|
| 查看次数: |
3551 次 |
| 最近记录: |