Description
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.
const component = new Vue({
computed: {
getNumber() {
return 42
}
}
})
component.getNumber // 42
By combining mapped types and keyof
, we can achieve some compile time types to capture this pattern.
declare interface Vue {
new <T extends {[k: string]: Function}>(config: {computed: T}): { [K in keyof T]: ReturnType<T[K]>}
}
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.
book.on({
"change:author": authorPane.update,
"change:title change:subtitle": titleView.update,
"destroy": bookView.remove
});
book.trigger("change:author", author)
// author should have the parameter type of authorPane.update
Also, with return/parameter/this type support, we can achieve typed bind/apply/call
interface FunctionTyped<ThisType, ArgTypes, RestArg> {
bind: FunctionTyped<void, [ThisType, ...ArgTypes], RestArg]>
apply: FunctionTyped<void, [ThisType, [...ArgTypes, ...RestArg]], never>
call: FunctionTyped<void, [ThisType, ...ArgTypes], RestArg>
}
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 is any
, the parameter type is Array<any>
.
To access function's parameter type, it might be good to reuse index access type. For example
type Callback = (a: Author) => void
type CallbackArg = Callback["arguments"] // [Author]
type CallbackReturn = Callback["returns"] // void, the access type is arguable
Related
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.