TypeScript如何在类型链中保留数值字面量信息?
TypeScript:仅允许函数返回的number,拒绝字面量数字的函数签名实现
问题分析
你需要设计一个函数签名,仅接受函数调用返回的number类型值,拒绝直接传入的字面量数字。目前尝试的类型判断逻辑能区分字面量和非字面量,但目标函数签名无法保留字面量类型信息,导致传入字面量时不会报错。
现有类型逻辑说明
你定义的两个核心类型是有效的:
Number_To_String<N extends number>:将数字类型转换为对应的字符串字面量类型Non_Literal_Number<Number extends string>:判断字符串是否为通用数字模板${number},若是则返回number,否则返回never(用于匹配字面量数字的字符串形式)
测试验证了类型逻辑的正确性:
type Test_Non_Literal = Non_Literal_Number<Number_To_String<number>> // number type Test_Literal = Non_Literal_Number<Number_To_String<42>> // never
但目标函数intended_signature存在问题:传入字面量时,TypeScript会自动将字面量拓宽为number类型,导致泛型参数Number被推断为number而非具体字面量,最终参数类型变成number而非预期的never。
解决方案:使用const泛型强制保留字面量类型
通过const泛型可以阻止TypeScript对字面量类型的自动拓宽,让泛型参数Number被推断为具体的字面量类型,从而触发Non_Literal_Number的正确判断。
修改后的函数签名如下:
type Non_Literal_Number<Number extends string> = `${number}` extends Number ? number : never type Number_To_String<N extends number> = `${N}` function intended_signature<const Number extends number>( number: Non_Literal_Number<Number_To_String<Number>> ) {} // 测试用例 function get_number() { return 0 } intended_signature(get_number()) // ✅ 正常通过:参数类型为number intended_signature(3) // ❌ 报错:类型“3”不能赋值给类型“never” intended_signature(123) // ❌ 报错:类型“123”不能赋值给类型“never”
原理说明
const Number extends number:强制TypeScript将传入的字面量推断为具体的字面量类型(如3、123),而非自动拓宽为number- 当传入函数返回的
number时,泛型参数Number被推断为number,Number_To_String<number>得到${number},Non_Literal_Number<${number}>返回number,参数类型匹配,正常通过 - 当传入字面量时,
Number被推断为具体字面量(如3),Number_To_String<3>得到"3",Non_Literal_Number<"3">返回never,字面量无法赋值给never,触发类型错误
关于辅助参数函数的报错问题
你之前的with_aux_param函数未报错,是因为泛型约束Aux extends ...仅作类型检查,但Aux未被实际使用(如作为返回值或参数类型)。若要让它报错,只需将Aux作为函数的返回值类型:
function with_aux_param<Number extends number, Aux extends Non_Literal_Number<Number_To_String<Number>>>(number: Number): Aux { return number as Aux } with_aux_param(8) // ❌ 报错:类型“8”不能赋值给类型“never”
内容的提问来源于stack exchange,提问作者Jarek
相关产品推荐
相关产品推荐

