I'm trying to create a polymorphic react-select wrapper, and am running into 'boolean' is assignable to the constraint of type 'Multi', but 'Multi' could be instantiated with a different subtype of constraint 'boolean'., where Multi is Multi extends boolean = false, which I do not understand even after doing a bunch of Googling (I'm convinced I'm setting the defaults in the right places and not shadowing anything, but here we are so clearly I'm not).
#Polymorphic component causing "could be instantiated with a different subtype of constraint"
12 messages · Page 1 of 1 (latest)
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
Just to explain what <Multi extends boolean = false> means. You can have a generic type:
type Foo<X extends boolean> { prop: X };
And you can use it as follows
const a: Foo<true> = { prop: true; } // a.prop is of type "true"
const b: Foo<false> = { prop: false; } // b.prop is of type "false"
const c: Foo<boolean> = { prop: foo; } // c.prop is of type boolean
// But you can't omit the type
const d: Foo = ... // error: Generic type 'Foo' requires 1 type argument.
Now, if you want to be able to omit the type argument, you can give it a default value. That's where the <... = false> comes in. If you defined the type as
type Foo<X extends boolean = false> { prop: X };
// Then if you write
const d: Foo = { prop: false } // Because you've omitted the generic type arg, X is defaulted to `false` so d.prop is of type "false"
This is an excellent write up on the cause of your exact error message
https://stackoverflow.com/questions/56505560/how-to-fix-ts2322-could-be-instantiated-with-a-different-subtype-of-constraint
Although it's a little over my head to see how this applies to your case. What I think is happening is you're typing an argument as <Multi extends boolean>, which may resolve to true, but you're assigning it to something which is generically typed as <Multi extends boolean>. Once it's been resolved to true it can't be assigned to something that accepts boolean.
In essence the Multi on line 31, is a different generic type from the Multi on line 25.
Yeah, I reached the same conclusion but cannot for the life of my figure out how to do it correctly
Admittedly I don't think the default here is at fault, removing all the defaults result in the same error still, even thought they're all typed as boolean and the generics are being passed around everywhere
@patent skiff I haven't looked closely, but in general, it's not really possible to do a generic component with forwardRef without just casting.
I'd figure out the type you want the external contract to look like and just cast whatever comes out of forwardRef.
(And look forward to React 19 making forwardRef obsolete)
Oh interesting, we've definitely make generics work with forwardRef before
For example: https://tsplay.dev/Wonngm
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
I think the main thing you really can't do is pass a generic function into forwardRef and have a generic function come out.