#Type is assignable to the constraint of type but could be instantiated with a different subtype
14 messages · Page 1 of 1 (latest)
Preview:```ts
type FooArgs<
A,
B extends {[k: string]: unknown}
= B & {
a: A
fn: (a: A, b: B) => void
}
function foo<A, B extends {[k: string]: unknown}>({
a,
fn,
...b
}: FooArgs<A, B>) {
fn(a, b)
// Is there a way to do this without casting?
// fn(a, b as B);
...```
Take this example:
function test(a: string, b: { a: string }) {}
foo({ a: 'test', fn: test })
test would be called with ('test', {}), and that would be a type error.
On a side note, your generic constraints on B aren't necessary.
Is there a way to infer B from fn's args or vis versa?
The problem isn't your type, it's inferred correctly.
It's your implementation, when you destructure FooArgs<A, B> into { a, fn, ...b }, b doesn't have a or fn anymore.
If B doesn't have a or fn, that's fine; but if it does like the example I gave, then it's a type error.
No, I want test to accept b: { a: string }
oh i see
so
function foo<A, B>(args: FooArgs<A, B>) {
const { fn, a } = args;
fn(a, args);
}
would be the solution to that issue
Yep, although you have to live with fn's args having excess a and fn properties if it didn't ask for them.
Depends on if that's acceptable to you, there are some alternatives if you are willing to change your API:
// change foo to
foo({ fn, a, options })
// change foo to
foo(fn, a, {
...options,
})
// change fn to accept { a, ...options }
// change foo to
foo(fn, {
a,
...options,
})