Reputation: 95
I want to do something like this:
type Item<T> = T & {
func: (v: T) => void
}
function a<What>(...items: Item<What>[]) {}
a({
name: "",
func: (v: {name: string}) => {}
}, {
count: 0,
func: (v: {count: number}) => {}
})
However above code will cause an error, how to do the similar thing with typscript?
Upvotes: 2
Views: 177
Reputation: 23825
You can utilize a syntax like this:
function a<T extends any[]>(...items: {
[K in keyof T]: T[K] & { func: (v: Omit<T[K], 'func'>) => void }
}) {}
A mapped type can be used to map over each element in items
. T[K]
always represents the current element, so we can use it to intersect itself with the function object.
// ok
a({
name: "",
func: (v: { name: string }) => {}
}, {
count: 0,
func: (v: { count: number }) => {}
})
// error
a({
name: 0,
func: (v: { name: string }) => {} /*
~~~~ Types of property 'name' are incompatible
*/
}, {
count: 0,
func: (v: { count: number }) => {}
})
For the implementation of the function, I would recommend to put all the complex generic stuff in an overload and to use a simpler signature for the implementing function.
function b<T extends any[]>(...items: {
[K in keyof T]: T[K] & { func: (v: Omit<T[K], 'func'>) => void }
}): void
function b(...items: ({ func: (arg: object) => void } & Record<string, any>)[]) {
for (const item of items) {
item.func({})
}
}
Upvotes: 2
Reputation: 464
I almost have it, however i cant get function to infer the generic on its own, but im sharing this anyway, in case someone else might solve it, or in case this helps you nontheless.
The trick i used to is to recursively infer each Item of What
, that way What
is properly handled as tuple and the Item constraint is applied to each element in What
seperately.
type Item<T> =
T & {func(v:T):void}
type Items<What> =
What extends [Item<infer A>, ...infer Rest]
? [Item<A>,...Items<[...Rest]>]
: What extends [] ? [] : never
function testFunction<What>(...items: Items<What>) {}
//this works, with an explicit generic
testFunction<[Item<{
name: string;
}>, Item<{
count: number;
}>]>({
name: "",
func: (v: {name: string}) => {}
}, {
count: 0,
func: (v: {count: number}) => {}
})
Upvotes: 2
Reputation: 10841
type Item<T> = T & {
func: (v: T) => void
}
function a<A extends Item<any>[]>(...items: A) {}
a({
name: "",
func: (v: {name: string}) => {}
}, {
count: 0,
func: (v: {count: number}) => {}
})
// ^?
// function a<[{
// name: string;
// func: (v: {
// name: string;
// }) => void;
// }, {
// count: number;
// func: (v: {
// count: number;
// }) => void;
// }]>(items_0: {
// name: string;
// func: (v: {
// name: string;
// }) => void;
// }, items_1: {
// count: number;
// func: (v: {
// count: number;
// }) => void;
// }): void
Upvotes: -1