【问题标题】:How to check custom interface type in Typescript如何在 Typescript 中检查自定义接口类型
【发布时间】:2020-04-26 03:32:42
【问题描述】:

我有

interface A {
  a_id: string;
  name: string;
}

interface B {
 b_id: string;
 name: string;
}

现在,我想检查一个对象说:

const myObj : A|B = {b_id: '1', name: 'one'};

如何查看类型,判断是属于A还是B

我尝试了few links,但获取类型不应该更容易吗?

【问题讨论】:

  • 你可能会觉得this很有趣。
  • @Ivan 您的链接还说,没有办法在运行时检查接口(我在想什么)。

标签: javascript typescript


【解决方案1】:

更新:所述问题并不表明请求能够在不检查属性的情况下区分类型。不幸的是,这是不可能的; TypeScript 编译为 JavaScript,这是实际运行的。而 TypeScript 的类型系统,在其中找到了 AB 这样的接口,在编译代码时完全是 erased。所以在运行时没有AB 可以检查。

如果您希望能够在运行时区分 myObjA 还是 B,则需要编写执行此操作的 JavaScript 代码...例如检查属性。您可以做的是使用 TypeScript 来帮助您编写此代码并对其进行分型,以便编译器也了解您的属性检查将A | B 缩小为AB。这就是这个答案的其余部分(以及另一个问题的答案)告诉你的。祝你好运!


other question's answer 建议你写一个user-defined type guard function,肯定可以的;这个想法是你告诉编译器你认为什么是区分AB的好方法,它会让你使用那个函数来做到这一点。

在您的情况下,一种更简单的方法是使用in 运算符,即can be used as a type guard(从TypeScript 2.7 开始)。例如:

declare const obj: A | B;
if ("b_id" in obj) {
  // obj is a B in here
  console.log(obj.name.toUpperCase());
} else {
  // obj is an A in here
  console.log(obj.a_id.toUpperCase());
}

请注意,这在技术上是不安全的,因为A | B 类型的对象可能无法以这种方式区分:

function getEvilAorB(): A | B {
  interface EvilA extends A {
    b_id: number;
  }
  const evilA: EvilA = { name: "", a_id: "", b_id: 123 };
  return evilA; // okay, EvilA extends A extends A | B
}

注意getEvilAorB() 返回一个有效的A,因此它是一个有效的A | B,但不幸的是它会因为数字name 属性而无法通过上述测试:

const evilA = getEvilAorB();
if ("b_id" in evilA) {
  console.log(evilA.b_id.toUpperCase()); // compiles but ? at runtime
  // TypeError! evilA.name.toUpperCase is not a function
}

如果您不关心这种边缘情况,那么in 类型防护可能就足够了。否则,您应该考虑编写用户定义的类型保护,或者使您的接口成为 discriminated union 的成员,这是让编译器区分联合成员的传统且受支持的方式。

希望有所帮助;祝你好运!

Playground link to code

【讨论】:

  • 您好,我在界面A中进行了一项更正。这是一个错字。真诚的歉意。我想忽略检查每个属性以确定类型。谢谢
【解决方案2】:

如果您能够更改这些接口的形状,对我来说是使用判别式的最简单方法。

interface A {
  discriminantKey: 'interfaceA';
  a_id: string;
  b_id: string;
}

interface B {
 discriminantKey: 'interfaceB';
 b_id: string;
 name: string;
}

当你在 swithc 情况下询问你的判别键时,即使在 typescript 中,你也会有类型保护,而不仅仅是 runetime。

const myType = {...}
switch(myType.discriminantKey) {
  case 'interfaceA':
    // here is type infered to 'A' interface;
   break
  case 'interfaceB':
    // here it is 'b'
}

playground

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    • 2021-01-24
    • 2021-06-19
    • 2015-07-27
    • 1970-01-01
    • 2020-11-01
    相关资源
    最近更新 更多