(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
,
name
和salary
属性。
如果您的界面有很多属性,这可能会变得非常冗长。
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
。
额外资源
您可以通过查看以下教程来了解有关相关主题的更多信息: