如何在TypeScript中检查运行时的对象类型?

Ede*_*971 17 types runtime typeof detect typescript

我正在尝试找到一种方法来传递一个对象来运行并在运行时检查它的类型.这是一个伪代码:

func(obj:any){
  if(typeof obj === "A"){
    // do something
  }
  else if(typeof obj === "B"{
    //do something else
  }

}
 a:A;
 b:B;
 func(a);
Run Code Online (Sandbox Code Playgroud)

但是typeof总是返回"对象",我找不到获得真正类型"a"或"b"的方法.instanceof也不起作用并返回相同的内容.知道如何在TypeScript中做到这一点吗?

谢谢您的帮助!!!

Aar*_*all 35

类型在编译时被剥离,并且在运行时不存在,因此您无法在运行时检查类型.

您可以做的是检查对象的形状是否符合预期,TypeScript可以使用用户定义的类型保护在编译时断言类型,如果形状符合您的期望,则返回true:

interface A {
  foo: string;
}

interface B {
  bar: number;
}

function isA(obj: any): obj is A {
  return obj.foo !== undefined 
}

function isB(obj: any): obj is B {
  return obj.bar !== undefined 
}

function func(obj: any) {
  if (isA(obj)) {
    // In this block 'obj' is narrowed to type 'A'
    obj.foo;
  }
  else if (isB(obj)) {
    // In this block 'obj' is narrowed to type 'B'
    obj.bar;
  }
}
Run Code Online (Sandbox Code Playgroud)

游乐场中的示例


Alp*_*33k 13

“我正在尝试找到一种方法来将对象传递给函数并在运行时检查它的类型”。

由于类实例只是一个object,“本机”答案是使用类实例,并且instanceof当需要运行时类型检查时,使用接口,而不是为了保持契约并解耦应用程序,减少方法/上的签名大小ctors,同时不添加任何额外的大小。以我的拙见,这是我在决定使用类与类型/接口时在 TypeScript 中考虑的几个主要考虑因素之一。另一个主要驱动因素是对象是否需要实例化,或者是否需要实例化 POJO。

在我的代码库中,我通常会有一个实现接口的类,并且该接口在编译期间用于预编译时类型安全,而类用于组织我的代码并允许在函数、类和方法之间轻松传递数据以及在打字稿中进行运行时类型检查。

有效,因为 routerEvent 是 NavigationStart 类的实例

if (routerEvent instanceof NavigationStart) {
  this.loading = true;
}

if (routerEvent instanceof NavigationEnd ||
  routerEvent instanceof NavigationCancel ||
  routerEvent instanceof NavigationError) {
  this.loading = false;
}
Run Code Online (Sandbox Code Playgroud)

不管用

// Must use a class not an interface
export interface IRouterEvent { ... }
// Fails
expect(IRouterEvent instanceof NavigationCancel).toBe(true); 
Run Code Online (Sandbox Code Playgroud)

不管用

// Must use a class not a type
export type RouterEvent { ... }
// Fails
expect(IRouterEvent instanceof NavigationCancel).toBe(true); 
Run Code Online (Sandbox Code Playgroud)

正如您从上面的代码中看到的,类用于将实例与NavigationStart|Cancel|ErrorAngular 库中的类型进行比较,如果您在项目之前使用过路由器,我愿意您在项目中进行了类似的检查(如果不是相同的检查)。自己的代码库,以便在运行时确定应用程序状态。

instanceof在类型或接口上使用是不可能的,因为 ts 编译器在其编译过程中以及在由 JIT 或 AOT 解释之前删除了这些属性。类是创建可在预编译以及 JS 运行时使用的类型的好方法。

2022 年更新

除了我最初对此的回应之外,您还可以利用TypeScript Reflect Metadata API或使用 TypeScript 编译器推出您自己的解决方案,对代码进行静态分析并解析 AST,查询如下:

switch (node.kind) {
  case ts.SyntaxKind.InterfaceDeclaration:
    // ...
    break;
  case ts.SyntaxKind.TypeDeclaration:
    // ...
    break;
}
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参阅此解决方案


小智 8

扩展了Aaron的答案,我制作了一个在编译时生成类型保护功能的转换器。这样,您不必手动编写它们。

例如:

import { is } from 'typescript-is';

interface A {
  foo: string;
}

interface B {
  bar: number;
}

if (is<A>(obj)) {
  // obj is narrowed to type A
}

if (is<B>(obj)) {
  // obj is narrowed to type B
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到该项目以及使用说明:

https://github.com/woutervh-/typescript-is

  • `typescript-is` 不好。他们强迫我使用`ttypescript`。 (3认同)