英文:
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=<S>(a: S) => S
type FooReturnType = ReturnType<Foo> // unknown
type Bar<S> = {
(a: S): S
}
type BarReturnType = ReturnType<Bar<string>> // 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
以下是翻译好的部分:
-
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 (likeBar
), but you need a value of typeFoo
(or you need to at least pretend to have such a value): -
And you can use higher order type inference from generic types to take a generic type like
Bar<S>
and convert it toFoo
, but you need to have (or pretend to have) a value of a type related toBar
: -
And you need to have a function that shuttles around arguments and return types:
-
And then operate on the former with the latter and get its type:
英文:
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 = <S>(a: S) => S
type Bar<S> = (a: S) => S
declare const foo: Foo;
type BarFromFoo<S> = typeof foo<S>; // instantiation expression
// type BarFromFoo<S> = (a: S) => S
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
:
declare const bar: <S>() => Bar<S>;
And you need to have a function that shuttles around arguments and return types:
declare const funWithFunctions: <A extends any[], B extends any[], R>(
f: (...a: A) => (...b: B) => R
) => (...ab: [...A, ...B]) => 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 = <S>(a: S) => S
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论