函数返回类型不可分配给泛型解析的内容

kst*_*tis 3 typescript typescript-generics

下面的TS代码有什么问题吗?

interface Animal {
  name: string;
}

interface Human {
  firstName: string;
  lastName: string;
}

type HumanName = { humanName: string };
type AnimalName = { animalName: string };

export const getDisplayName = <TItem extends Animal | Human>(
  item: TItem
): TItem extends Human ? HumanName : AnimalName => {
  if ("firstName" in item) {
    return { humanName: `${item.firstName} ${item.lastName}` };  // squiggly line
  } else {
    return { animalName: item.name };  // squiggly line
  }
};
Run Code Online (Sandbox Code Playgroud)

将鼠标悬停在波浪线上,这是我得到的错误:

Type '{ humanName: string; }' is not assignable to type 'TItem extends Human ? HumanName : AnimalName'.ts(2322)
Run Code Online (Sandbox Code Playgroud)

这是游乐场链接

片段灵感来自传奇人物 Matt Pocock 的技巧

Twi*_*her 5

您的问题是,在函数实现中,泛型类型未解决,因此您不能将其视为 anAnimal或 aHuman而不显式转换它。

泛型类型仅为调用者解析。

解决您的问题的一种可能的解决方案是利用函数重载来编写两个签名:

  • 为调用者强类型化的一种
  • 一个松散类型的实现(在鸭子类型方面与第一个兼容)
interface Animal {
  name: string;
}

interface Human {
  firstName: string;
  lastName: string;
}

type HumanName = { humanName: string };
type AnimalName = { animalName: string }; 

function getDisplayName<TItem extends Animal | Human>(item: TItem): TItem extends Human ? HumanName : AnimalName
function getDisplayName(item: Animal | Human): HumanName | AnimalName {
  if ("firstName" in item) {
    return { humanName: `${item.firstName} ${item.lastName}` };  // item: Human
  } else {
    return { animalName: item.name };  // item: Animal
  }
}

const animalName = getDisplayName({ name: 'cat' }); // AnimalName
const humanName = getDisplayName({ firstName: 'Guerric', lastName: 'P' }); // HumanName
Run Code Online (Sandbox Code Playgroud)

TypeScript 游乐场