基于TypeScript中其他变量的类型检查

brvekthn  于 2023-05-19  发布在  TypeScript
关注(0)|答案(1)|浏览(139)

在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;
  }
}
von4xj4u

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保护校验的别名,也不是判别并集的判别属性的别名。因此不会发生缩窄。
既然你想做的事情是不可能的,你就必须围绕它工作。一般来说,最干净和最受支持的方法是通过向每个成员添加判别式属性,然后检查判别式,将并集变为判别式并集:

type A = { stateIndicator: "stateA", prop1: string }
type B = { stateIndicator: "stateB", prop2: number }

function foo(data: A | B) {
    if (data.stateIndicator === "stateA") {
        const myString: string = data.prop1;
    } else {
        const myNumber: number = data.prop2;
    }
}

但显然,您的用例将驱动解决方案的选择。
Playground链接到代码

相关问题