简体   繁体   English

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

[英]TypeScript: How to write a function with conditional return type

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 }
}

I am playing around with the conditional types in TypeScript.我正在玩 TypeScript 中的条件类型。 i would like to write a function with a conditional return type.我想写一个有条件返回类型的函数。 If the function gets passed a string it returns a Name otherwise it returns an Id.如果函数被传递一个字符串,它返回一个名称,否则返回一个 Id。

I get the following error on my return statements:我的返回语句出现以下错误:

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

What am I missing?我错过了什么? Thnx!谢谢!

Edit: The example taken directly from Anders Hejlsberg talk at Build 2018: https://youtu.be/hDACN-BGvI8?t=2241编辑:直接取自 Anders Hejlsberg 在 Build 2018 上的演讲的示例: https ://youtu.be/hDACN-BGvI8?t =2241

He even states "we do not have to write function overloads anymore..."他甚至说“我们不必再写函数重载了……”

If I change the code to just a declaration, the compile errors go away:如果我将代码更改为仅声明,编译错误就会消失:

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

So we can declare the function signature.所以我们可以声明函数签名。 I guess my question then becomes, how would we actually implement the function?我想我的问题变成了,我们将如何实际实现该功能?

The problem is inside the function T is not known, so you can't really assign a value to Value<T> .问题在于函数T内部未知,因此您无法真正为Value<T>赋值。 One option would be to use a type assertion.一种选择是使用类型断言。 A more type safe option would be to use a separate implementation signature, that would be more relaxed about the input and output type:更类型安全的选项是使用单独的实现签名,这样输入和输出类型会更宽松:

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 }
}

Here is another solution which works great as well.这是另一个效果很好的解决方案。

I like this solution better than the accepted answer because you will get correct type deduction when coding :我比接受的答案更喜欢这个解决方案,因为您在编码时会得到正确的类型推导

在此处输入图片说明

You can see when hovering, it correctly deduced the type.你可以看到当悬停时,它正确地推断出类型。

Here is the code from the screenshot:这是屏幕截图中的代码:

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>
}

I'm not sure I understand your example fully, but I think this is what you want?我不确定我是否完全理解你的例子,但我认为这就是你想要的?

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 }
}

See, that I've removed any generics from your example, since I don't see the need for them in this case看,我已经从您的示例中删除了任何泛型,因为在这种情况下我认为不需要它们

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM