Typescript不';无法使用泛型扩展字符串联合类型推断正确的类型? type Test='a'|'b'|'c'; 函数foo(arg:T){ 如果(arg=='a'){ 控制台日志(arg); } }
像这样。。我希望在if块中使用arg推断的“a” 但是ts推断为T 为什么会出现这种情况Typescript不';无法使用泛型扩展字符串联合类型推断正确的类型? type Test='a'|'b'|'c'; 函数foo(arg:T){ 如果(arg=='a'){ 控制台日志(arg); } },typescript,typescript-typings,Typescript,Typescript Typings,像这样。。我希望在if块中使用arg推断的“a” 但是ts推断为T 为什么会出现这种情况 我认为extends关键字有点 问题是,您的类型T不是Test,而是一个子集,我们可以说每个类型都可以用来代替T,而每个for联合都意味着一个具有相同或更少联合成员的类型。考虑扩展代码< >代码>测试>代码>: type Test = 'a' | 'b' | 'c'; function foo<T extends Test>(arg: T) { if (arg === 'a') {
我认为
extends
关键字有点 问题是,您的类型T
不是Test
,而是一个子集,我们可以说每个类型都可以用来代替T
,而每个for联合都意味着一个具有相同或更少联合成员的类型。考虑扩展代码< >代码>测试>代码>:
type Test = 'a' | 'b' | 'c';
function foo<T extends Test>(arg: T) {
if (arg === 'a') {
console.log(arg);
}
}
正如您所看到的,SubTest
没有a
成员,但它可分配给Test
,因此我们可以对这种类型使用foo
函数
type Test = 'a' | 'b' | 'c';
type SubTest = 'b' | 'c'
type IsSubTest = SubTest extends Test ? true : false // evaluates to true
一切都很好,没有错误。但是这意味着你的条件arg==='a'
永远不会满足,因为子测试中没有成员a
,这就是为什么TS不能假设在我们使用a
的条件内,因为在这种情况下,这个分支是完全不可到达的,并且在它的内部将是类型永远不
。我们甚至可以编写这样的函数并检查:
const arg: SubTest = 'b'
foo(arg)
好的,但即使TS没有缩小到a
,因为条件很清楚,任何通过它的东西都将是a
,这里毫无疑问
让我们尝试手动复制原始条件中存在的相同类型的保护,该条件检查左侧值(从测试扩展)是否等于右侧值(从测试扩展)
函数isTestMember(x:x,y:y):x是y{
返回x==y//错误我们无法将x的成员与y的成员进行比较
}
正如你所看到的,这样的字体保护甚至不能被书写。由于X和Y不能重叠,因此条件X===Y
对X
和Y
的所有成员无效
<> P.Ts不能考虑类型不能重叠的条件作为类型守卫,因此类型没有变窄。< /P>有趣。如果您编写了arg:string
,那么它确实正确地缩小了范围,因此它肯定与T是一个类型变量有关。但是如果你没有一个extends
子句,那么它认为t
和string
没有重叠,所以无法测试它是否是由extends
引起的。这看起来像一个bug,但可能是有原因的。虽然问题本身可能很有趣,但上面示例中的泛型是无用的。只需使用函数foo(arg:Test).
@AlekseyL。您可以假设这只是一个演示问题的例子,而不是实际的用例。如果您定义函数isTestMember(x:Test,y:y):x是y{return x==y}
,那么foo
函数工作正常,并且arg
在If&/code>块内被推断为类型T'a'
。因此,我认为对于某些t
来说,条件并不总是可以满足这一事实并不重要。但是x不是Test,而是t扩展Test
,那又怎样x
可分配给Test
,因为x:T
和T扩展了Test
。仅仅因为T&'a'
可能没有填充,并不意味着我们不能在适当的类型保护之后将x
缩小到该类型;在这里,工作没有错误。在这种情况下,isTestMember
调用的返回类型被推断为x是'a'
,它将x
的范围缩小为T&'a'
,因此问题是为什么arg===='a'
的工作方式不一样。T&'a'
可以计算为never
,当我们有像子测试
这样的类型时,它将完全是从不
T&a
与justT
function foo(arg: SubTest) {
if (arg === 'a') { // compilation error, condition will be always false
console.log(arg);
}
}
function isTestMember<X extends Test, Y extends Test>(x: X, y: Y): x is Y {
return x == y // error we cannot compare member of X with member of Y
}