如何告诉 TypeScript,将一个不那么严格的接口转换成更严格的接口是可以的?

3

我正在尝试执行我下面粘贴的代码,但是TypeScript编译器似乎并不相信我已经正确地确保了一个接口可以基于我所做的检查转换为另一个。我需要做什么才能使它对这段代码满意?


interface Person {
  name: string,
  address?: string
}

interface PersonWithAddress extends Person {
  address: string
}

function tryLoggingAddresses(people: Array<Person>) {
  people.forEach(person => {
    if (person.address) {
      logAddress(person)
    }
  })
}

function logAddress(personWithAddress: PersonWithAddress) {
  console.log(personWithAddress.address)
}

Typescript错误:

error TS2345: Argument of type 'Person' is not assignable to parameter of type 'PersonWithAddress'.
      Types of property 'address' are incompatible.
        Type 'string | undefined' is not assignable to type 'string'.
          Type 'undefined' is not assignable to type 'string'.

    63       logAddress(person)

我知道我可以通过更改该行代码为logAddress(person as PersonWithAddress)来强制进行类型转换,但这实际上禁用了所有的类型检查,这并不理想。有没有什么方法可以在不进行这种类型转换的情况下实现呢?


一个用户定义的类型守卫是否可行?例如,function isPersonWithAddress(object: Person): object is PersonWithAddress { return 'address' in object; }。像这样调用它:if (isPersonWithAddress(person)) { logAddress(person); } - D M
1
如果您只需要“地址”,那么这可能更简单:https://tsplay.dev/m3PByW - Alex Wayne
很遗憾,@AlexWayne,这只是一个玩具示例,在实际代码中我需要验证的不仅仅是地址。不过还是谢谢你的建议。 - Alex Long
1个回答

2
你可以使用类型保护来替换现有的条件表达式。这将帮助编译器在控制流分析期间确定数据结构符合你的意图。

TypeScript 演示台

function personHasAddress (person: Person): person is PersonWithAddress {
  return typeof person.address === 'string';
}

function logAddresses (people: Person[]) {
  for (const person of people) {
    if (personHasAddress(person)) logAddress(person);
  }
}

太棒了!在这之前我从未听说过类型守卫。谢谢! - Alex Long

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接