Reputation: 44416
I'm trying to wrap a function that take an argument of some specific type to create a function that take an argument of a slightly different type. Here is the code, slightly simplified:
type DifferentArgs<T> = {
myNewArg: number;
} & T;
function f<T, U>({ myNewArg, ...t }: DifferentArgs<T>, g: (q: T) => U) {
return g(t);
}
This seems logical to me: t
will necessarily be assignable to T
.
The compiler disagrees:
'Pick<DifferentArgs<T>, Exclude<keyof T, "myNewArg">>' is
assignable to the constraint of type 'T', but 'T' could
be instantiated with a different subtype of constraint '{}'
Can someone explain how there could be a different T
and how I can fix this?
Upvotes: 2
Views: 31
Reputation: 44416
Wow, that took me a long time.
Here's the problem. Imagine the above code did compile. Further imagine you are trying to call f()
like so:
type KillerType = {
myNewArg(): void;
}
f( k, (kt: KillerType) => kt.myNewArgs());
Now there is no value you can use for k
that makes sense. It would have to have the property myNewArg
both be a number and a void-valued function, a clear impossibility. Even ignoring the type-checking problem, f()
would call the anonymous function without any myNewArg
value at all.
It can be fixed:
type DifferentArgs<T> = {
myNewArg: number;
} & T;
type SameArgs<T> = Omit<T, 'myNewArg'>;
function f<T, U>({ myNewArg, ...t }: DifferentArgs<T>,
g: (q: SameArgs<T>) => U): U {
return g(t);
}
Basically, you have to promise the compiler that the parameter to g
will never need a property called myNewArg
so the conflict can never arise.
Upvotes: 1