TypeScript中如何让自定义标签模板函数返回对应字符串字面量类型
问题核心原因
默认情况下TypeScript会将模板标签函数接收的TemplateStringsArray内的字符串元素类型宽化为string,不会保留原始的字面量类型,所以直接对TemplateStringsArray做泛型约束无法拿到精确的字面量类型。
解法1:适配无插值场景(兼容TS 4.x及以上版本)
通过元组类型强制捕获字符串的字面量类型,再和TemplateStringsArray交叉,既符合类型定义又能保留字面量信息:
function taggedLiteral<T extends string>(strings: [T, ...string[]] & TemplateStringsArray): T { return strings[0] } const test: 'foobar' = taggedLiteral`foobar` // 无报错,test类型自动推导为"foobar"
解法2:适配带插值场景(TS 5.0+可用)
配合TS 5.0引入的const类型参数,递归拼接模板字符串和插值的类型,实现完整字面量返回:
// 递归拼接模板字符串与插值的类型 type JoinTemplate<S extends readonly string[], V extends readonly unknown[]> = S extends [infer First extends string, ...infer RestS extends readonly string[]] ? V extends [infer FirstV, ...infer RestV extends readonly unknown[]] ? `${First}${FirstV}${JoinTemplate<RestS, RestV>}` : First : "" function taggedLiteral<const S extends readonly string[], const V extends readonly unknown[]>( strings: S & TemplateStringsArray, ...values: V ): JoinTemplate<S, V> { return String.raw(strings, ...values) as never } // 测试无插值 const test1 = taggedLiteral`foobar` // 类型推导为"foobar" // 测试带插值 const num = 123 const str = "test" const test2 = taggedLiteral`foo${num}bar${str}` // 类型推导为"foo123bartest"
内容的提问来源于stack exchange,提问作者Alex Wayne
相关产品推荐
相关产品推荐

