如何区分字符串插值中的number与bigint类型?
TypeScript字符串插值中区分number与bigint类型的方法
在TypeScript中,模板字面量类型的字符串插值不会区分number和bigint的字符串表示(比如${1}和${1n}都会得到字符串"1"),导致通过字符串反向推断原类型时出现不符合预期的结果:
type Test1<T extends string> = T extends `${infer R extends bigint}` ? R : never type Test2<T extends string> = T extends `${infer R extends number}` ? R : never type _result1 = Test1<'1'> // ^? type _result1 = 1n // 预期为never type _result2 = Test1<`${1n}`> // ^? type _result2 = 1n // 符合预期 type _result3 = Test2<'1'> // ^? type _result3 = 1 // 符合预期 type _result4 = Test2<`${1n}`> // ^? type _result4 = 1 // 预期为never
可行的区分方案
方案1:修改字符串格式,添加类型标识
通过给bigint的插值字符串添加独特后缀(比如n),让两种类型的字符串格式产生差异,从而在类型推断时区分:
// 仅匹配带n后缀的bigint字符串 type Test1<T extends string> = T extends `${infer R extends bigint}n` ? R : never // 仅匹配不带n后缀的number字符串 type Test2<T extends string> = T extends `${infer R extends number}` ? (T extends `${string}n` ? never : R) : never type _result1 = Test1<'1'> // never(符合预期) type _result2 = Test1<'1n'> // 1n(符合预期) type _result3 = Test2<'1'> // 1(符合预期) type _result4 = Test2<'1n'> // never(符合预期)
这种方案需要调整插值方式,比如将${1n}改为${1n}n,确保bigint的字符串带有明确标识。
方案2:通过泛型关联原类型元数据
如果需要保留默认的字符串格式,可以通过泛型将字符串类型与原类型绑定,利用元数据区分:
// 给字符串类型添加原类型标记 type TaggedString<T> = T extends bigint ? `${T}` & { __tag: 'bigint' } : T extends number ? `${T}` & { __tag: 'number' } : never; // 仅接受标记为bigint的字符串 type Test1<T extends TaggedString<bigint>> = T extends `${infer R extends bigint}` ? R : never; // 仅接受标记为number的字符串 type Test2<T extends TaggedString<number>> = T extends `${infer R extends number}` ? R : never; type _result1 = Test1<TaggedString<1>> // 类型报错(符合预期,因为TaggedString<1>是number标记的字符串) type _result2 = Test1<TaggedString<1n>> // 1n(符合预期) type _result3 = Test2<TaggedString<1>> // 1(符合预期) type _result4 = Test2<TaggedString<1n>> // 类型报错(符合预期,因为TaggedString<1n>是bigint标记的字符串)
这种方案需要在创建字符串类型时就关联原类型的标记,确保类型系统能识别字符串的来源。
说明
如果不修改字符串格式也不添加元数据,仅通过字符串内容无法区分number和bigint的表示——因为两者的字符串输出(比如"1")完全重叠,TypeScript的类型系统无法仅凭字符串内容判断其原始类型。
内容的提问来源于stack exchange,提问作者zedryas
相关产品推荐
相关产品推荐

