TypeScript:如何编写具有条件返回类型的函数

时间:2018-06-01 11:04:00

标签: typescript

export type Name = { name: string }
export type Id = { id: number }
export type Value<T> = T extends string ? Name : Id

export function create<T extends string | number>(value: T): Value<T> {
    if (typeof value === "string") return { name: value }

    return { id: value }
}

我正在玩TypeScript中的条件类型。我想用条件返回类型编写一个函数。如果函数传递了一个字符串,则返回一个Name,否则返回一个Id。

我在退货声明中收到以下错误:

Type '{ name: T & string; }' is not assignable to type 'Value<T>'.

我错过了什么?日Thnx!

编辑:直接来自Anders Hejlsberg的例子在Build 2018上发表演讲: https://youtu.be/hDACN-BGvI8?t=2241

他甚至声明&#34;我们不再需要编写函数重载...&#34;

如果我将代码更改为声明,编译错误就会消失:

export type Name = { name: string }
export type Id = { id: number }

export type Value<T> = T extends string ? Name : Id

declare function create<T extends string | number>(value: T): Value<T>

const a = create("Bob")     // a : Name
const b = create(5)         // b : Id

所以我们可以声明函数签名。我想我的问题就变成了,我们将如何实际实现这个功能?

3 个答案:

答案 0 :(得分:4)

问题出在函数T内部未知,因此您无法为Value<T>分配值。一种选择是使用类型断言。更安全的类型选项是使用单独的实现签名,对输入和输出类型更加宽松:

export function create<T extends string | number>(value: T): Value<T> // public signature
export function create(value: string | number): Name | Id { // more relaxed private implementation signature 
    if (typeof value === "string") return { name: value }

    return { id: value }
}

答案 1 :(得分:2)

这是另一个效果很好的解决方案。

与接受的答案相比,我更喜欢这种解决方案。因为在编码时会得到正确的类型推导

enter image description here

您可以看到鼠标悬停时,可以正确推断出类型。

这是屏幕截图中的代码:

export type Name = { name: string }
export type Id = { id: number }
export type Value<T extends string | number> = T extends string ? Name : Id

export function create<T extends string | number>(value: T): Value<T> {
    if (typeof value === 'string') return { name: value } as unknown as Value<T>

    return { id: value } as unknown as Value<T>
}

答案 2 :(得分:0)

我不确定我完全理解你的例子,但我认为这就是你想要的?

type Name = { name: string }
type Id = { id: number }
type Value = Name | Id

export function create(value: string | number): Value {
  if (typeof value === "string") return { name: value }
  return { id: value }
}

请注意,我已从您的示例中移除了任何泛型,因为在这种情况下我不会发现它们的必要性