TypeScript类型转换函数写法:为何instanceof不适用于接口及正确方案
问题
我写了一段TypeScript代码,想用instanceof判断参数的接口类型,但完全不起作用。代码如下:
interface PetrolEngineProperties { cylinders: number; capacity: number; } interface ElectricEngineProperties { numberOfBatteries: number; batteryCellSize: number; } function initializeCarEngine(engineProperties: PetrolEngineProperties | ElectricEngineProperties) { if (engineProperties instanceof ElectricEngineProperties) { // 处理电动引擎逻辑 } else if (engineProperties instanceof PetrolEngineProperties) { // 处理燃油引擎逻辑 console.log('Petrol engine was started'); } }
想请教:为什么instanceof判断接口类型会失效?这类带类型分支的函数该怎么写才规范?
为什么instanceof无法判断接口类型?
TypeScript的接口是编译时专属的类型定义,编译成JavaScript后,所有接口相关的代码都会被彻底移除——JavaScript运行时根本不知道这些接口的存在。而instanceof是JavaScript的运行时运算符,它只能判断对象是否是某个构造函数(类)的实例,依赖的是对象的原型链信息。接口没有对应的构造函数,自然没法用instanceof来判断。
规范写法
1. 属性检查式类型守卫
通过检查对象是否包含某个接口特有的属性,让TypeScript自动收窄类型,这是最常用的方式:
interface PetrolEngineProperties { cylinders: number; capacity: number; } interface ElectricEngineProperties { numberOfBatteries: number; batteryCellSize: number; } function initializeCarEngine(engineProperties: PetrolEngineProperties | ElectricEngineProperties) { // 检查电动引擎特有的属性 if ('numberOfBatteries' in engineProperties) { // 这里TypeScript会自动识别engineProperties为ElectricEngineProperties类型 console.log(`电动引擎,电池数量:${engineProperties.numberOfBatteries}`); } else { // 自动识别为PetrolEngineProperties类型 console.log(`燃油引擎,气缸数:${engineProperties.cylinders}`); console.log('Petrol engine was started'); } }
2. 自定义类型守卫函数
如果需要更复杂的判断逻辑,可以写一个自定义的类型守卫函数,明确告诉TypeScript如何判断类型:
interface PetrolEngineProperties { cylinders: number; capacity: number; } interface ElectricEngineProperties { numberOfBatteries: number; batteryCellSize: number; } // 自定义类型守卫:判断是否为电动引擎属性 function isElectricEngine(properties: any): properties is ElectricEngineProperties { return 'numberOfBatteries' in properties && 'batteryCellSize' in properties; } // 自定义类型守卫:判断是否为燃油引擎属性 function isPetrolEngine(properties: any): properties is PetrolEngineProperties { return 'cylinders' in properties && 'capacity' in properties; } function initializeCarEngine(engineProperties: PetrolEngineProperties | ElectricEngineProperties) { if (isElectricEngine(engineProperties)) { console.log(`电动引擎,电池单体容量:${engineProperties.batteryCellSize}`); } else if (isPetrolEngine(engineProperties)) { console.log(`燃油引擎,排量:${engineProperties.capacity}`); console.log('Petrol engine was started'); } }
3. 改用类代替接口(如果需要运行时类型)
如果确实需要用instanceof判断,那可以把接口改成类——类编译后会保留构造函数和原型链,这样instanceof就能正常工作:
class PetrolEngineProperties { constructor(public cylinders: number, public capacity: number) {} } class ElectricEngineProperties { constructor(public numberOfBatteries: number, public batteryCellSize: number) {} } function initializeCarEngine(engineProperties: PetrolEngineProperties | ElectricEngineProperties) { if (engineProperties instanceof ElectricEngineProperties) { console.log(`电动引擎,电池数量:${engineProperties.numberOfBatteries}`); } else if (engineProperties instanceof PetrolEngineProperties) { console.log(`燃油引擎,气缸数:${engineProperties.cylinders}`); console.log('Petrol engine was started'); } } // 使用示例 const petrolEngine = new PetrolEngineProperties(4, 2.0); initializeCarEngine(petrolEngine);
内容的提问来源于stack exchange,提问作者TMS
相关产品推荐
相关产品推荐

