TypeScript 中 Error: Type ‘X’ has no properties in common with type ‘Y’ 解决方法

当我们在属性没有重叠的情况下尝试将任何内容分配给弱类型时,会出现错误“Type ‘X’ has no properties with type ‘Y’”。 要解决该错误,需要声明任何重叠属性(如果存在)或使用类型断言。

按照惯例,我们先来看一段产生该错误的代码

interface Employee {
  id?: number;
  salary?: number;
}

function getEmployee(emp: Employee) {
  return emp;
}

// 与 Employee 的属性没有重叠
const emp = {
  name: 'James',
};

// Error: Type '{ name: string; }' has no
// properties in common with type 'Employee'.ts(2559)
getEmployee(emp);

然后我们运行上面的代码,它会产生错误 “error TS2559: Type ‘{ name: string; }’ has no properties in common with type ‘Employee’”。 具体结果如下所示

TypeScript 中 Error: Type 'X' has no properties in common with type 'Y' 解决方法

Employee 类型是一个弱类型,因为它的所有属性都是可选的。

问号用于将类型的属性标记为可选,表示该属性可以是特定类型也可以是未定义的。

Employee 类型是一个弱类型,因为我们可以创建一个符合该类型的空对象。

interface Employee {
  id?: number;
  salary?: number;
}

// 这是可以的
const e: Employee = {};

错误的原因是 – 我们将 emp 对象传递给一个需要 Employee 类型对象的函数,并且 emp 变量与 Employee 类型没有重叠。

解决错误的一种方法是使用类型断言。

interface Employee {
  id?: number;
  salary?: number;
}

function getEmployee(emp: Employee) {
  return emp;
}

const emp = {
  name: 'James',
};

// {name: 'James'}
getEmployee(emp as Employee); // 使用类型断言

另一种解决方案是确保 Employee 类型和 emp 对象之间存在重叠。 例如,我们可以将 name 属性添加到 Employee 类型。

interface Employee {
  id?: number;
  salary?: number;
  name?: string; // 添加 name
}

function getEmployee(emp: Employee) {
  return emp;
}

const emp = {
  name: 'James',
};

// {name: 'James'}
console.log(getEmployee(emp));

我们将 name 属性添加到 Employee 类型,所以现在类型和 emp 对象之间存在重叠。这样就可以解决上面的错误,因为属性有重叠。

如果无法更改类型,则可以向对象添加重叠属性。

interface Employee {
  id?: number;
  salary?: number;
}

function getEmployee(emp: Employee) {
  return emp;
}

const emp = {
  name: 'James',
  id: 0, // 添加属性 id
};

// {name: 'James'}
console.log(getEmployee(emp));

我们给emp对象添加了id属性,所以Employee类型和对象有重叠,也解决了报错。

错误 “Type ‘X’ has no properties in common with type ‘Y’” 也可以通过使用索引签名来解决。

interface Employee {
  id?: number;
  salary?: number;
  [key: string]: any; // added index signature
}

function getEmployee(emp: Employee) {
  return emp;
}

const emp = {
  name: 'James',
};

// {name: 'James'}
console.log(getEmployee(emp));

{[key: string]: any} 语法是 TypeScript 中的索引签名,当我们事先不知道类型属性的所有名称和值的形状时使用。

示例中的索引签名意味着当 Employee 类型的对象使用字符串进行索引时,它将返回任何类型的值。

我们不必使用 any 作为类型,可以更具体来制定类型从而获得更安全的保证。 但是,请注意,索引签名的类型必须是接口中所有可能类型的联合类型。

interface Employee {
  id?: number;
  salary?: number;
  // 具有更安全的类型的索引签名
  [key: string]: string | number | undefined;
}

const e: Employee = {};

function getEmployee(emp: Employee) {
  return emp;
}

const emp = {
  name: 'James',
};

// {name: 'James'}
console.log(getEmployee(emp));

我们指定当一个 Employee 类型的对象被一个字符串键索引时,它将返回一个字符串、数字或未定义类型的值。

这是必要的,因为我们的 id 和 salary 属性具有 number 或 undefined 类型的值(因为它们是可选的),并且 id 和 salary 也是字符串键。

这种方法消除了错误。因为 Employee 类型现在涵盖了任何字符串键,因此 Employee 类型和 emp 变量之间存在重叠