typescript 具有相同字段的类型的类型保护

8hhllhi2  于 2023-03-09  发布在  TypeScript
关注(0)|答案(1)|浏览(138)

我偶然发现了结构类型的一个局限性,想知道是否有办法绕过它。
假设我有一个如下的类型层次结构:

type Message = HelloMessage | GoodbyeMessage

type HelloMessage = {
  message: string
}

type GoodbyeMessage = {
  message: string
}

并且我们定义一些类型保护如下:

function isHello(value: any): value is HelloMessage {
    return !!value && !!value.message && typeof value.message === "string" && value.message.includes("hello")
}

function isGoodbye(value: any): value is GoodbyeMessage {
    return !!value && !!value.message && typeof value.message === "string" && value.message.includes("goodbye")
}

试图在函数中使用类型保护会导致编译器将后续使用类型指定为never

function someFunc(input: Message): string {
    if (isHello(input)) {
        return input.message
    }
    if (isGoodbye(input)) {
        return input.message // compiler errors here
    }
    return "unknown"
}

一些明显的解决方案是在if语句中将输入键入为any或将input强制转换为GoodbyeMessage,但这两种方法都不太优雅,这仅仅是Typescript的type结构特性的限制,还是可以使用其他魔法使其按我所期望的方式工作?

6ie5vjzr

6ie5vjzr1#

你是对的,这是类型系统的一个局限性,即使类型保护起作用了,你也不能 * 实际上 * 分辨出一个函数传递的是HelloMessage还是GoodbyeMessage,因为它看到的只是{ message: string },你可以使用一个带标记的联合类型,可以用类型保护来区分它:

type Message = HelloMessage | GoodbyeMessage;

type HelloMessage = {
  type: "hello";
  message: string;
}

type GoodbyeMessage = {
  type: "goodbye";
  message: string;
}

// Prefer to use `unknown` for additional type safety.
function isHello(value: unknown): value is HelloMessage {
  return typeof value === "object"
      && value !== null
      && "type" in value
      && typeof value.type === "string"
      && value.type === "hello";
}

function isGoodbye(value: unknown): value is GoodbyeMessage {
  return typeof value === "object"
      && value !== null
      && "type" in value
      && typeof value.type === "string"
      && value.type === "goodbye";
}

相关问题