Typescript - 缩小函数返回类型的类型联合范围

发布于 2025-01-09 10:32:14 字数 2482 浏览 0 评论 0原文

为什么 Typescript 无法区分其类型来自函数返回类型的类型联合,而无需在函数上显式声明返回类型?

这里我没有指定事件创建函数的返回值,并且联合类型不能缩小。

enum EventType {
  FOO = "foo",
  GOO = "goo",
}

function createFooEvent(args: {
  documentId: number | null
}) {
  return {
    type: EventType.FOO,
    data: args
  }
}
function createGooEvent(args: {
  id: number
  isSelected: boolean
}) {
  return {
    type: EventType.GOO,
    data: args
  }
}

type EventArgType =
  | ReturnType<typeof createFooEvent>
  | ReturnType<typeof createGooEvent>

function eventHandler(event: EventArgType) {
  switch(event.type) {
    case EventType.FOO: {
      // Note that `event` contains `data` but `data`'s type is a union and has not been discriminated
      event.data;
      break
    }
  }
}

但是,如果我按如下方式指定返回类型,则可以区分联合。

function createFooEvent(args: {
  documentId: number | null
}): {
  type: EventType.FOO,
  data: {
    documentId: number | null
}} {
  return {
    type: EventType.FOO,
    data: args
  }
}
function createGooEvent(args: {
  id: number
  isSelected: boolean
}): {
  type: EventType.GOO,
  data: {
    id: number
    isSelected: boolean
}} {
  return {
    type: EventType.GOO,
    data: args
  }
}

<一href="https://www.typescriptlang.org/play?#code/PTAEDkHlwWgdUgJQNIElwHFQFgBQeAzAVwDsBjAFwEsB7E0AUwA8BDAWwAcAbByEhgBQBKAN55QjEkTagAogDcGJCgBUAnhwagx uCRIBikSKAC8oAEQEaNcwBpxejEdMWA5tbsOAvngfFy1HSgZABODCwUDPrWCkoUAiwhrgDOAFzaDhiAJjRk0nGoWelSbABGDCGgAD6gUlxc3kIZunphFEQh9Dp6ehQaDOmxyuqaAHSGkPYtPVkR LOmJKZmgPi2rEv6UtPSh4ZEYMYrKCUlpzT1URbXS5SHLVMkAygw8lAxXpdY8LCSN560Mdqdf4 9PqaQZHVT9UZOSbLbJzBanZbrFa+FpgrRDCgAQSSIy0JmWNUQgI6JAJAB5MTQCMEwhEooc4gA+ YmgULAin9an9Wn0vYMA40bFs-AtTaBegMSEACR+WR4IQEMriELieNcBKa3T0yQA7lQKGQABYqyGjTE6+HBFjJLGQgnjIzpXU9CQgCA0SKgCgmiKgAAGquUgeCdAoLCoJGSQdmkbDpSIFDjc0DAH JY5jQA9QCxQKRtnmSFlQP7YyRvaBykpQFkHqEqGxo4ysjaJCGKKN4ywanzt6sMgDWNtRELRq1 WeE9CBQj3RkqLzHY3AYK​​n1NGE-yU0jkjv6INAExclg8Ux6sJP7hs57R4o9YHA3q0foDfq0bXJv v6sf57-taoRDQlSLnQsa5sw3BUGQRplhUWjyFmJpaMunA8HmnyKH4pBbEuyMtEIqQicKSuss OR5GwBRXCUtzVNc9SNGR0zfuCe5xE6Ey3gikbMe6da5PkyiFMUNwVPRdQNGsXiHp+wJur0-Tqs M0JcTaPZIksLETthARFvh+zMscixnAplyiWUFT3E8LwMG8HxfOEvxrEIfGKWx2JOrC3F1oih4SOZ1yWXcLEBTZryRA5NDfM544yQpcldDamLKVCYzeepfkmSi3johI2bYpqBKmOynLklSNJ0gZT JEaypVkp0FV8lVDKGbVyhirpuHSnKCpKuaarscoRX9NaLEGkapoDcolqjf5toAZ5qkuvND5ej 6r4psGkJhmQEZRjGqYJsWpaBj2GZZge5bVgwtb1skjbNiQrYDp23ZzP2oV6KUw6jjlax4KsQA" rel="nofollow noreferrer">这是 TS Playground 中的示例。

Why is it that Typescript cannot discriminate a type union whose types are from the return types of function, without explicitly declaring the return type on the function?

Here I do not specify the return values of the event creator functions and the union type cannot be narrowed.

enum EventType {
  FOO = "foo",
  GOO = "goo",
}

function createFooEvent(args: {
  documentId: number | null
}) {
  return {
    type: EventType.FOO,
    data: args
  }
}
function createGooEvent(args: {
  id: number
  isSelected: boolean
}) {
  return {
    type: EventType.GOO,
    data: args
  }
}

type EventArgType =
  | ReturnType<typeof createFooEvent>
  | ReturnType<typeof createGooEvent>

function eventHandler(event: EventArgType) {
  switch(event.type) {
    case EventType.FOO: {
      // Note that `event` contains `data` but `data`'s type is a union and has not been discriminated
      event.data;
      break
    }
  }
}

But if I specify the return types as follows then the union can be discriminated.

function createFooEvent(args: {
  documentId: number | null
}): {
  type: EventType.FOO,
  data: {
    documentId: number | null
}} {
  return {
    type: EventType.FOO,
    data: args
  }
}
function createGooEvent(args: {
  id: number
  isSelected: boolean
}): {
  type: EventType.GOO,
  data: {
    id: number
    isSelected: boolean
}} {
  return {
    type: EventType.GOO,
    data: args
  }
}

Here is an example in TS playground.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦途 2025-01-16 10:32:14

因为默认情况下,typescript 不会将常量推断为类型: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions

例如:

var a = 'test'

Typescript 将推断类型a 作为 string 而不是 'test'

您可以使用 as const 修复它:

var a = 'test' as const;

在这种情况下,a 的类型将为 'test'

您的代码也是如此:

  function createFooEvent(args: {
    documentId: number | null
  }) {
    return {
      type: EventType.FOO,
      data: args
    };
  }

函数的返回类型是 {type: EventType} 而不是 {type:'foo'}

as const 添加到返回类型,将按照您的预期工作TS 游乐场

function exampleOne(){
  enum EventType {
    FOO = "foo",
    GOO = "goo",
  }

  function createFooEvent(args: {
    documentId: number | null
  }) {
    return {
      type: EventType.FOO,
      data: args
    } as const;
  }
  function createGooEvent(args: {
    id: number
    isSelected: boolean
  }) {
    return {
      type: EventType.GOO,
      data: args
    } as const;
  }

  type EventArgType =
    | ReturnType<typeof createFooEvent>
    | ReturnType<typeof createGooEvent>

  function eventHandler(event: EventArgType) {
    switch(event.type) {
      case EventType.FOO: {
        // event.data in this case will be {documentId: number|null}
        event.data;
        break
      }
    }
  }
}

Because typescript does not infer the constant as the type by default: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions

For example:

var a = 'test'

Typescript will infer type of a as string not as 'test'.

You can fix it using as const:

var a = 'test' as const;

In this case a will be of type 'test'.

Same for your code:

  function createFooEvent(args: {
    documentId: number | null
  }) {
    return {
      type: EventType.FOO,
      data: args
    };
  }

The return type of the function is {type: EventType} instead of {type:'foo'}.

Adding as const to the return type, will work as you expect TS Playground

function exampleOne(){
  enum EventType {
    FOO = "foo",
    GOO = "goo",
  }

  function createFooEvent(args: {
    documentId: number | null
  }) {
    return {
      type: EventType.FOO,
      data: args
    } as const;
  }
  function createGooEvent(args: {
    id: number
    isSelected: boolean
  }) {
    return {
      type: EventType.GOO,
      data: args
    } as const;
  }

  type EventArgType =
    | ReturnType<typeof createFooEvent>
    | ReturnType<typeof createGooEvent>

  function eventHandler(event: EventArgType) {
    switch(event.type) {
      case EventType.FOO: {
        // event.data in this case will be {documentId: number|null}
        event.data;
        break
      }
    }
  }
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文