I have the following function
function fun<T extends boolean>(param: T): void {
param = true
}
When I assign param
to true
, the compiler gives me the following error:
Type 'boolean' is not assignable to type 'T'.
'boolean' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'boolean'.ts(2322)
Why can't I assign it? T
is (or at least extends) boolean
, so it should work.
There is a workaround to add <T>
before true
or as T
after true
, but that's just annoying to do all the time.
It's also more annoying when you try to add a default value to param
:
function fun<T extends boolean>(param: T = true): void
Now there is an error on param: T = true
which is the same exact one as the previous error.
Why can't I just assign to param
without explicitly type-asserting (adding <T>
or as T
) the value?
Basically, just because you have two different sub types does not mean you can assign one to other.
true
and false
are subtypes, but if a value explicitly expects the value false, you cannot assign true right.
It is a little difficult to find practical examples with primitives, but with objects it does make a lot of sense. And, in JS anything can be an object :D.
I hope the below snippet is helpful. Here we have both kinds of example. Please check the comments too:
function fun<T extends boolean>(param: T): void {
param = true //The error
}
const val: false = false; //val can only be false
type PrimitiveWithRandomFunc = false & { func? : () => void };
type ExtendsWrong = PrimitiveWithRandomFunc extends boolean ? true : false;
let m :false & { func? : () => void } = false; //m can only be false and have a func in addition
m.func = () => {
console.log("yolo");
}
fun(val) //no error, although we are assigning true to val, which should be false
fun(m) //no error
If one is to create a type like PrimitiveWithRandomFunc
, which is possible in JavaScipt, then the above error makes sense.
ExtendsWrong
is true
type, which means the extension constraint is match. But just because it is matched does not mean that we can assign a different subtype to param
.
Notice how fun(m)
does not give any error. I am using func
as optional property to get rid of some TS errors, but I hope it gets the point across. Basically you would be assigning true to something that only expects fale and some other things.
And for val
I hope it is clearly apparent, we are simply able to assign true
to something that should be false
.