Reputation: 385
I have a {string: Function}
map a
:
const a: A = {
foo: (x: string) => 8,
bar: (y: number, z: boolean) => 6,
}
I then transform it such that every mapped function has a different type of return value:
const b: B = {
foo: (x: string) => (8).toString(),
bar: (y: number, z: boolean) => (6).toString(),
}
In TypeScript, is there any way to describe type B
as derived from A
, in my dream world, I'd like to be able to do:
type A = {
foo: (string) => number
bar: (number, boolean) => number
}
type B = {
[K in keyof A]: (E in argsof A[K]) => string
}
Upvotes: 3
Views: 89
Reputation: 41
You can achieve this using the built in Parameters<T>
type as of Typescript 3.1:
type B = {
[K in keyof A]: (...a: Parameters<A[K]>) => string
}
This isn't explicitly documented in the Typescript docs on conditional types but similar conditional types are, like ReturnType<T>
, you can see them all in the source.
With this in mind we could go a step further and relate B to the return type of our transforming function using ReturnType<T>
:
const transformingFunction: (n: number) => string = (n: number) => n.toString();
type B = {
[K in keyof A]: (...a: Parameters<A[K]>) => ReturnType<typeof transformingFunction>
}
So now, if we want to change the return type of our transforming function, it can be done in one place, i.e. on the function itself without breaking the signature of B.
Upvotes: 3
Reputation: 250196
Dreams come true in Typescript :)
You can achieve this in Typescript 3.0 using conditional types and Tuples in rest parameters and spread expressions:
type A = {
foo: (s: string) => number
bar: (n: number, b: boolean) => number
}
type ArgumentTypes<T extends (...a: any[]) => any> = T extends (...a: infer A) => any ? A : [];
type B = {
[K in keyof A]: (...a:ArgumentTypes<A[K]>) => string
}
let b: B;
b.foo("") // works
b.foo(1) // error
Upvotes: 5