如何在TypeScript中在运行时检查对象类型?
如何在TypeScript中在运行时检查对象类型?
我正在尝试找到一种在运行时将对象传递给函数并检查其类型的方法。这是一个伪代码:
function func(obj: any) { if (obj instanceof A) { // 做一些事情 } else if (obj instanceof B) { // 做另一些事情 } } let a: A; let b: B; func(a);
但是 `typeof` 总是返回 `"object"`,我找不到获取 `a` 或 `b` 的实际类型的方法。 `instanceof` 也不起作用,返回相同的结果。
有什么办法可以在 TypeScript 中实现这个功能吗?
在TypeScript中,编译时会去除类型信息,因此在运行时无法直接检查对象的类型。但是可以通过检查对象的形状来判断其类型,并使用TypeScript的用户定义类型保护来在编译时断言类型是否匹配。
用户定义类型保护是一种返回true的类型谓词形式,用于在编译时断言对象的形状是否符合预期。通过定义一个函数,检查对象的特定属性是否存在来实现用户定义类型保护。例如,下面的示例中定义了两个接口A和B,以及两个函数isA和isB用于检查对象是否符合A和B的形状:
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; }
在func函数中,使用if语句来检查对象的类型,并在相应的代码块中进行类型缩小。例如,如果对象符合A的形状,则在if语句的代码块中,可以安全地访问对象的foo属性:
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; } }
通过使用用户定义类型保护,可以在编译时断言对象的类型,并在相应的代码块中进行类型缩小,从而安全地访问对象的属性或方法。
需要注意的是,用户定义类型保护只需要返回true或false,具体的形状检查的深度取决于实际情况。在上述示例中,只检查了对象的属性是否存在,而没有检查属性的类型。如果需要检查属性的类型,需要根据具体情况进行相应的形状检查。
,虽然在TypeScript中无法直接在运行时检查对象的类型,但可以通过检查对象的形状并使用用户定义类型保护来在编译时断言对象的类型是否匹配。这种方法可以确保在访问对象的属性或方法时不会出现类型错误。
如何在TypeScript中在运行时检查对象类型?
问题的原因是作者想要在运行时将一个对象传递给函数,并检查其类型。根据作者的观点,当需要进行运行时类型检查时,可以使用类实例和instanceof
。而在不需要运行时类型检查时,可以使用接口来保持契约并解耦应用程序,从而减小方法/构造函数的签名大小,而不会增加额外的大小。作者在自己的代码库中通常会有一个实现接口的类,接口用于编译时类型安全性,而类用于组织代码并在函数、类和方法之间轻松传递数据,以及在TypeScript中进行运行时类型检查。
上述代码中,使用类来将实例与Angular库中的类型NavigationStart|Cancel|Error
进行比较,如果您之前使用过路由器,我相信您在自己的代码库中已经进行了类似或相同的检查,以确定运行时的应用程序状态。
在TypeScript中无法对类型或接口使用instanceof
,因为TypeScript编译器在其编译过程中会剥离这些属性,并在JIT或AOT解释之前。类是一种非常好的方式,可以在编译前和JS运行时中使用的类型。
2022年更新:
除了我对此的最初回答外,您还可以利用TypeScript Reflect Metadata API或使用TypeScript编译器自己的解决方案,通过对代码进行静态分析和解析AST来查询,例如:
switch (node.kind) { case ts.SyntaxKind.InterfaceDeclaration: // ... break; case ts.SyntaxKind.TypeDeclaration: // ... break; }
您可以参考上述链接中的解决方案,了解更多详细信息。
在TypeScript中,我们有时候需要在运行时检查对象的类型。这个问题出现的原因是因为在TypeScript中,类型信息只在编译时存在,而在运行时被擦除。因此,如果我们想要在运行时检查对象的类型,我们需要使用一些技巧来实现。
解决这个问题的方法之一是使用一个库叫做typescript-is。这个库提供了一个类型守卫函数is
import { is } from 'typescript-is'; interface A { foo: string; } interface B { bar: number; } if (is(obj)) { // obj is narrowed to type A } if (is(obj)) { // obj is narrowed to type B }
通过使用typescript-is库,我们可以很方便地在运行时检查对象的类型,并根据类型进行相应的操作。
如果你想要了解更多关于typescript-is库的信息,你可以在这里找到项目的链接:[https://github.com/woutervh-/typescript-is](https://github.com/woutervh-/typescript-is)。在这个链接中,你可以找到使用该库的说明。
另外,有人可能会对typescript-is库使用了ttypescript这个库感到不满。其实,你并不是被强制使用ttypescript库,你也可以使用typescript API来编译你的项目,并自己配置转换器。ttypescript库只是被推荐的方式,因为它为你做了这些工作。当你使用一个转换器时,目前没有其他选择。另外,ttypescript有什么问题呢?;-)
对于不想添加另一个编译器的人来说,我认为ttypescript是一个好的解决方案。如果你使用typescript-is库,你需要添加另一个编译器或者编写自己的编译逻辑,这会增加额外的复杂性。
总结一下,通过使用typescript-is库,我们可以在TypeScript中实现在运行时检查对象类型的功能。这是因为TypeScript中的类型信息只在编译时存在,而在运行时被擦除。使用typescript-is库,我们可以方便地在运行时检查对象的类型,并根据类型进行相应的操作。虽然有人对使用ttypescript库感到不满,但它是一种被推荐的方式,因为它为你处理了一些工作。如果你不想添加另一个编译器,typescript-is库是一个很好的选择。