(instanceof) ‘X’ 仅指类型,但在这里用作值

(instanceof) ‘X’ 仅指类型,但在这里用作值

(instanceof) ‘X’ Only refers to a type, but is being used as a value here

当我们尝试将运算符与类型而不是值一起使用时,会出现“instanceof”错误“仅指类型,但在此处用作值” instanceof

要解决该错误,请改为创建一个类,或者简单地使用用户定义的类型保护。

仅指类型但被用作值

下面是错误如何发生的示例。

索引.ts
interface Employee { name: string; salary: number; } let emp: Employee; // ⛔️ 'Employee' only refers to a type, but is being used as a value here.ts(2693) if (emp instanceof Employee) { console.log(emp.salary); }

错误是因为我们使用了

类型而不是值的
instanceof运算符。

instanceof运算符返回一个布尔值,指示构造函数的原型属性是否出现在对象的原型链中。

instanceof与类一起使用

解决该错误的一种方法是使用类而不是
接口

索引.ts
class Employee { constructor(public name: string, public salary: number) { this.name = name; this.salary = salary; } } const emp = new Employee('Bobby Hadz', 100); if (emp instanceof Employee) { // 👇️ this runs console.log('✅ is instance of Employee'); } console.log(emp instanceof Employee); // 👉️ true

emp对象是使用该类创建的Employee,因此它是该类的一个实例。

设置类属性

如果在实例化类时不打算采用参数,也可以设置类属性。

索引.ts
class Employee { name = ''; salary = 0; tasks: string[] = []; } const emp = new Employee(); emp.name = 'Bobby Hadz'; emp.salary = 100; emp.tasks.push('test'); if (emp instanceof Employee) { // 👇️ this runs console.log('✅ is instance of Employee'); } console.log(emp instanceof Employee); // 👉️ true

但是,您可以拥有一个满足类型但不是类实例的对象,因为它不是使用特定类创建的。

索引.ts
class Employee { constructor(public name: string, public salary: number) { this.name = name; this.salary = salary; } } // 👇️ Correct type, but not an instance const emp2: Employee = { name: 'Bobby Hadz', salary: 200, }; console.log(emp2 instanceof Employee); // 👉️ false const emp = new Employee('Tom', 100); console.log(emp instanceof Employee); // 👉️ true

变量emp2不是Employee类的实例,即使它满足类型。原因是它不是使用类创建的。

使用用户定义的类型保护代替instanceof

如果您需要测试特定对象是否正确实现了类型,请使用用户定义的类型保护

索引.ts
interface Employee { id: number; name: string; salary: number; } function isAnEmployee(obj: any): obj is Employee { return 'id' in obj && 'name' in obj && 'salary' in obj; } const emp: Employee = { id: 3, name: 'Bobby Hadz', salary: 300, }; console.log(isAnEmployee(emp)); // 👉️ true console.log(isAnEmployee({ id: 1 })); // 👉️ false if (isAnEmployee(emp)) { // 👉️ TypeScript knows that emp is type Employee console.log(emp.id); // 👉️ 3 console.log(emp.name); // 👉️ "Bobby Hadz" console.log(emp.salary); // 👉️ 300 }

我们使用
用户定义的类型保护
来检查对象是否
实现了接口

语法obj is Employee是类型谓词,其中必须是函数采用的参数的名称。 obj

如果isAnEmployee函数返回true,TypeScript 知道传入的值是类型的Employee,并允许我们访问特定接口上的所有属性和方法。

上面的示例只是检查传入的对象是否包含id,
namesalary属性。

如果您的界面有很多属性,这可能会变得非常冗长。

type给接口添加一个属性

另一种方法是
向 interface
添加一个type属性,您改为检查该属性。

索引.ts
interface Employee { id: number; name: string; salary: number; type: 'Employee'; // 👈️ add type property } function isAnEmployee(obj: any): obj is Employee { // 👇️ check for type property return 'type' in obj && obj.type === 'Employee'; } const emp: Employee = { id: 3, name: 'Bobby Hadz', salary: 300, type: 'Employee', }; console.log(isAnEmployee(emp)); // 👉️ true console.log(isAnEmployee({ id: 1 })); // 👉️ false if (isAnEmployee(emp)) { console.log(emp.id); // 👉️ 3 console.log(emp.name); // 👉️ "Bobby Hadz" console.log(emp.salary); // 👉️ 300 console.log(emp.type); // 👉️ "Employee" }

Employee接口有一个type字符串文字值为 的属性
Employee这意味着具有类型的所有对象都Employee将具有此属性。

在我们的函数中,我们所要做的就是检查传入的对象是否具有type
等于 的属性
Employee

额外资源

您可以通过查看以下教程来了解有关相关主题的更多信息: