在TypeScript中,是否可以有一个变量来指示其他变量的类型?最后,我只想检查一个变量stateIndicator
,它依赖于其他变量来假设它们的类型。
type A = {prop1: string}
type B = {prop2: number}
function isA(x: A | B): x is A {
return (x as A).prop1 !== undefined
}
function foo1(data: A | B) {
const stateIndicator = isA(data);
if (stateIndicator) {
// this is fine
const myString: string = data.prop1;
}
}
function foo2(data: A | B) {
const stateIndicator = isA(data) ? "stateA" : "stateB";
if (stateIndicator === "stateA") {
// here unless I check if isA(data) or do "data as A" the data.prop1 shows error
// Property 'prop1' does not exist on type 'B'
const myString: string = data.prop1;
}
}
1条答案
按热度按时间von4xj4u1#
不,你正在寻找的东西在TypeScript中是不可能的。请参阅microsoft/TypeScript#46915以获得规范答案。
一般来说,TypeScript编译器无法跟踪代码的所有可能的逻辑结果。也就是说,它不会进行 * 反事实推理 *,如“在
foo2()
的主体中,如果stateIndicator
是"stateA"
,则必须意味着isA(data)
返回true
,因为如果返回false
,则stateIndicator
将是"stateB"
,其不等于"stateA"
,并且没有其他方法可以证明stateIndicator
是"stateA"
。因此data
必须是A
“。一般来说,做这样的事情太昂贵了。在大多数情况下,对一个变量(如
stateIndicator
)执行的任何检查最多只会影响该变量本身的表观类型,而不会影响历史可能与它纠缠在一起的其他变量。所以stateIndicator === "stateA"
缩小了stateIndicator
本身,但没有其他东西。即使检查对象的属性,通常也只会影响该属性的表观类型,而不会影响父对象的表观类型,除非父对象是区分联合类型,并且检查的属性是其判别式。有几个案例确实发生了这样的事情。TypeScript 4.4引入了 aliased 条件和判别式的控制流分析。这意味着,如果你将yes-no类型保护的
boolean
结果赋给const
,或者将判别并集的判别属性赋给const
,那么对该const
的后续检查将缩小相关变量的类型。这就是让您的foo1
实现工作的原因;stateIndicator
是一个别名类型保护boolean
。但是在foo2
中,stateIndicator
既不是boolean
保护校验的别名,也不是判别并集的判别属性的别名。因此不会发生缩窄。既然你想做的事情是不可能的,你就必须围绕它工作。一般来说,最干净和最受支持的方法是通过向每个成员添加判别式属性,然后检查判别式,将并集变为判别式并集:
但显然,您的用例将驱动解决方案的选择。
Playground链接到代码