在 TypeScript 中转换两种泛型函数类型

huangapple go评论54阅读模式
英文:

Converting between the two types of generic functions in typescript

问题

以下是翻译好的部分:

"有没有办法在这两种通用函数之间进行转换:

type Foo = <S>(a: S) => S
type FooReturnType = ReturnType<Foo> // unknown

type Bar<S> = {
  (a: S): S
}
type BarReturnType = ReturnType<Bar<string>> // string

即从类型 Foo 转换为类型 Bar,以及从类型 Bar 转换为类型 Foo

当使用泛型定义函数时,它采用类型 Foo 的形式。然而,当传递返回类型时,如果采用类型 Bar 的形式,会更有用。

一种解决方案是单独定义返回类型,使用泛型,然后在函数中使用它。但这会分散你的代码,使其变得更加混乱。"

英文:

Is there any way to convert between these two kinds of generic function:

type Foo=&lt;S&gt;(a: S) =&gt; S
type FooReturnType = ReturnType&lt;Foo&gt;          // unknown

type Bar&lt;S&gt; = {
  (a: S): S
}
type BarReturnType = ReturnType&lt;Bar&lt;string&gt;&gt;  // string

I.e. convert from type Foo to type Bar, and Bar to Foo?

When one defines a function with generics is takes the form of type Foo. However when passing the return type type around, it is much more useful if it takes the form of Bar.

One solution is to define the return type separately, using generics, and then to use that in one's function. However this splits one's code, and makes it messier.

答案1

得分: 1

以下是翻译好的部分:

  1. There is currently no way purely at the type level to convert between generic types and generic call signatures. The scope of the generic type parameters are different, and although there is a logical relationship between them, this relationship cannot be properly expressed in the type system. For that to happen we'd probably need true higher kinded types as requested in microsoft/TypeScript#1213, or possibly generic values as requested in microsoft/TypeScript#17574, or possibly existentially quantified generics as requested in microsoft/TypeScript#14466. And we don't have direct support for any of those (as of TS5.0).

  2. The language does have some limited ability to represent this sort of thing, but it all involves dropping down to the value level. That is, you need to have a value of the relevant type, and then you can perform some operation on that value to compute something that has the type you want. Depending on your use cases, this sort of value-level code might be sufficient.

  3. For example, instantiation expressions let you convert a specific type representing a generic call signature (like Foo) into a generic type representing a specific call signature (like Bar), but you need a value of type Foo (or you need to at least pretend to have such a value):

  4. And you can use higher order type inference from generic types to take a generic type like Bar<S> and convert it to Foo, but you need to have (or pretend to have) a value of a type related to Bar:

  5. And you need to have a function that shuttles around arguments and return types:

  6. And then operate on the former with the latter and get its type:

Playground link to code

英文:

There is currently no way purely at the type level to convert between generic types and generic call signatures. The scope of the generic type parameters are different, and although there is a logical relationship between them, this relationship cannot be properly expressed in the type system. For that to happen we'd probably need true higher kinded types as requested in microsoft/TypeScript#1213, or possibly generic values as requested in microsoft/TypeScript#17574, or possibly existentially quantified generics as requested in microsoft/TypeScript#14466. And we don't have direct support for any of those (as of TS5.0).


The language does have some limited ability to represent this sort of thing, but it all involves dropping down to the value level. That is, you need to have a value of the relevant type, and then you can perform some operation on that value to compute something that has the type you want. Depending on your use cases, this sort of value-level code might be sufficient.

For example, instantiation expressions let you convert a specific type representing a generic call signature (like Foo) into a generic type representing a specific call signature (like Bar), but you need a value of type Foo (or you need to at least pretend to have such a value):

type Foo = &lt;S&gt;(a: S) =&gt; S
type Bar&lt;S&gt; = (a: S) =&gt; S 

declare const foo: Foo;
type BarFromFoo&lt;S&gt; = typeof foo&lt;S&gt;; // instantiation expression
// type BarFromFoo&lt;S&gt; = (a: S) =&gt; S

And you can use higher order type inference from generic types to take a generic type like Bar&lt;S&gt; and convert it to Foo, but you need to have (or pretend to have) a value of a type related to Bar:

declare const bar: &lt;S&gt;() =&gt; Bar&lt;S&gt;;

And you need to have a function that shuttles around arguments and return types:

declare const funWithFunctions: &lt;A extends any[], B extends any[], R&gt;(
    f: (...a: A) =&gt; (...b: B) =&gt; R
) =&gt; (...ab: [...A, ...B]) =&gt; R // higher order generic function inference

And then operate on the former with the latter and get its type:

const fooFromBar = funWithFunctions(bar)
type FooFromBar = typeof fooFromBar;
// type FooFromBar = &lt;S&gt;(a: S) =&gt; S

Playground link to code

huangapple
  • 本文由 发表于 2023年2月10日 16:49:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/75408779.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定