Repository navigation
Feature request: represent Function via generic type parameterized by its return/parameter/this type #12342
Description
Activity
See also #6606
In your specific example, wouldn't
declare interface Vue { new <T extends {[k: string]: Function}>(config: {computed: { [K in keyof T]: () => T[K]}}): T }
Be an equivalently correct type (without need for a special type function), provided T were inferred correctly?
HerringtonDarkholme commented
on Nov 19, 2016 ContributorAuthorMore actionsWesley Wigham (@weswigham) I believe T could not be inferred correctly for now by design: mapped type is not an inference site. #12114 (comment)
Herrington Darkholme (@HerringtonDarkholme) note the comment:
You could speculate about the compiler manufacturing a structurally compatible type, but that is generally not something we do and there are lots of subtle ways it could go wrong and lead to confusing error messages
Accumulating valuable use cases, such as this, is how things like this can change. 👍
Reacted by Herrington Darkholme- changed the title
[-]Feature request: function return/parameter/this type [/-][+]Feature request: Represent Function via generic type parameterized by its return/parameter/this type [/+]on Nov 20, 2016 - changed the title
[-]Feature request: Represent Function via generic type parameterized by its return/parameter/this type [/-][+]Feature request: represent Function via generic type parameterized by its return/parameter/this type [/+]on Nov 20, 2016 i have a use case that is similar.
declare interface StoreProps<A> { actions: A } declare function Store<A> (props: StoreProps<A>): StoreImpl<A>; declare interface StoreImpl<A> { commit<CK extends keyof A, CT extends A[CK] & { (x: P): void }, P>(k: CK, r: P): void } let s = Store({ actions: { act: function(x: number) {} } }) s.commit("act", "")
I'm trying to make type checker to derive second argument type using value of first argument here. And VSCode correctly shows that type of second generic parameter in call to
s.commit("act", "")should be{ (x: number): void } & { (x: string): void }
on mouseover hint.

I was hoping that i could make compiler to derive type of A[CK] and give error if type is illegal. This type is obviously illegal (argument can't be string and number at the same time), so compilation should fail and VSCode should show it as error, but it currently doesn't.I think some kind of type deconstruction will be good here. So could write, for example,
commit<CK extends keyof A, A[CK] is {(x: P): RT}>(k: CK, r: P): void
, where
isdeconstructs A[CK] and gives access to function's argument type and return type, depending on literal type of first argumentEdit: sorry, tested a bit more and i think i understand now, why i have no compilation error.
let x: { (x: number): void } & { (x: string): void } = (p: string|number) => {}
compiles as well, so looks like
{ (x: number): void } & { (x: string): void }doesn't meanxis of typestring & number. Just that function should be able to be called with both string and number parameters, but type deconstruction would be still usefull, because i used this partCT extends A[CK] & { (x: P): void }, Pjust to tell compiler thatA[CK]should be a function of certain type and i cannot do it without getting types of arguments fromA[CK]KiaraGrouwstra commented
on Nov 29, 2016 ContributorMore actionsTracking this as well, wanna type
mapover heterogeneous structures (tuples, objects).@tycho01 looks at #1213
That's going to be a great step towards generalization of functions. I like it. However, it would not be enough. Next things to consider are:
- capture function overloads, in general (any proposal/discussion?)
- capture generic parameters of function (Function composition challenge for type system #10247)
I happen to need full on return type rewriting for my particular use case. To pull from #12381, I need a transformation from
Original<T>toWrapped<T>to properly type my API (I'm currently using type parameters and a whole lot ofany, but that's incredibly ugly):interface Original<T> { [P in keyof T]: (...args) => R; } interface Wrapped<T> { [P in keyof T]: (...args) => Promise<R>; }
Reacted by Tamás HegedűsWhat is the status of this? It seems to me like adding the proposed
ReturnTypewould be a very nice improvement for adding types to many real-world functions.Below is an example of a function that cannot be given a correct type without this feature (note that I use
ReturnTypein the definition ofApplyObject):type ApplyObject<O extends Record<string, Pair>> = { [K in keyof O]: ReturnType<O[K]> } // Takes an object of functions, calls each function and returns an object with the results function applyObject<O extends { [p: string]: () => any }>(object: O): ApplyObject<O> { const newObject: any = {}; for (const key of Object.keys(object)) { newObject[key] = object[key](); // <- Note application here } return newObject; }
How about instead, create a new type-level operator (instead of a native generic) called
returnof. To take Simon Friis Vindum (@paldepind)'s example:type ApplyObject<O extends Record<string, Pair>> = { [K in keyof O]: returnof O[K] }
It fits better with the theme of using syntax instead of generics for primitive type-level operations.
- addedNeeds InvestigationThis issue needs a team member to investigate its status.This issue needs a team member to investigate its status.
on May 24, 2017 HerringtonDarkholme commented
on Feb 13, 2018 ContributorAuthorMore actionsI think this usage is already covered by conditional type. Closing.
KiaraGrouwstra commented
on Feb 14, 2018 ContributorMore actionsYeah. For reference, see this
Fntype implementation based on a similar discussion at gcanti/typelevel-ts#8.
Well, minus thethisbinding requested here. And no way to represent return types based on inputs.- locked and limited conversation to collaborators
on Jul 3, 2018
Background:
With #11929, we can get property type of an object. But we cannot get the return/parameter/this types of a function at compile time.
For single function argument, getting return/parameter type is relative simple by adding generic parameter. But when API is designed to accept a map of functions, it become hard to express in TypeScript.
Using function is a common pattern in vuejs and its derivation.
By combining mapped types and
keyof, we can achieve some compile time types to capture this pattern.If only we have a special type called
ReturnType.Another usage is for event handling in most frontend framework. For example, backbone has an event-map syntax for event binding.
Also, with return/parameter/this type support, we can achieve typed bind/apply/call
Note, this would require variadic generic types.
Proposal:
For every function type, we can have a special access key for return type/ parameter type. Parameter type is a tuple type for every argument. If function has rested parameter, parameter type will fallback to array type.
For overloaded function, the return type/parameter type is the union of all corresponding type of overloading signature.
For generic type parameter with function type constraint, the return type is resolved to constraint. the parameter type also resolves to constraint's parameter type (not regarding with variance.) If generic type has no constraint, resolve it to
{}.For
Function, the return and parameter type isany, the parameter type isArray<any>.To access function's parameter type, it might be good to reuse index access type. For example
Related
#212
#1773
Edit: I think representing function via typed generic is a more complete solution. But it requires more typing features as prerequisites and rewriting all function type encoding.