打字稿推断关键字推断错误的类型?

时间:2021-03-10 11:46:55

标签: typescript types type-inference

使用这样的简单结构:

type Test<Source extends string[]> = 
    Source extends [infer Head, ...infer Tail] ? `${Head}${Head}` : never;

Typescript 抱怨 ${Head}${Head} 中的字符串插值说:Type `'Head'` is not assignable to type 'string | number | bigint | boolean'. Type 'Head' is not assignable to type 'number'.ts(2322)

...这对我来说没有多大意义,但我的搜索没有取得成果。 Source 必须是 string[] 所以 Head,如果存在,必须是一个字符串,对吗?所以 ${Head} 必须完全有效。为什么 TS 抱怨无法将其分配给 number?字符串也可以分配给 "string | number | bigint | boolean" 所以这个错误对我来说没有多大意义。我可以通过在 "Head extends string ? ... : ... 子句之间放置字符串插值来修复它,但我想知道为什么首先需要这样做。

2 个答案:

答案 0 :(得分:1)

是和否。 看看下一个例子:

type Test0<Source extends string[]> =
    Source extends [infer Head, ...infer Tail] ? Head : never;

type O = Test0<[never, 'a']> // no error, because that is how NEVER works

因为 string|never 返回 string

我认为在上述情况下检查 Head 是否为字符串要安全得多。

答案 1 :(得分:1)

错误的原因是 TypeScript 在推断类型之前不会考虑 extends string[] 约束。如果你看这种类型

type T<Head> = `${Head}`

您会看到相同的相当迟钝的错误消息(对模板文字的推断有点不稳定)。由于 T 不在这里推断 Head,您当然可以只声明 type T<Head extends string> = ..,但另一种选择是在额外的条件中对 Head extends string 约束进行编码:

type T<Head> = Head extends string ? `${Head}` : never

这就是为什么 Test 类型检查您是否添加了额外的、看似多余的条件:

type Test<Source extends string[]> = 
    Source extends [infer Head, ...infer Tail] 
    ? Head extends string ? `${Head}${Head}` : never 
    : never;

TypeScript playground