I am trying to learn TS for the first time, but there is one case, which does not click quite well in my mind. Let's say we have two variables:
let value1: 'POST' | number | boolean = 'POST';
let value2: 'POST' | number | boolean | string = 'POST';
And let's say we have another variable to which we want to assign one of the variables specified above:
let copiedValue: 'POST'
When I assign to the variable copiedValue variable labeled value1 it works okay, but when I attempt to assign value2 complier shows me an error and I have to cast it to get rid of this error. I suppose that is because of additional string type that I added to value2 variable and TS compiler just warns that if something is labeled as a string it can be anything and not only 'POST', but is not it a problem that value1 variable has boolean and numeric types set on it too? Also, if TS compiler allows value1 because it knows that this variable holds "POST" at the moment of assignment to copiedValue variable, what is a problem with value2 variable if it also holds absolutely the same "POST" value?
CodePudding user response:
is not it a problem that value1 variable has boolean and numeric types set on it too?
In general, yes it is.
However, in your case you have assigned 'POST'
to value1
. This allows the compiler to infer that, at that point in the program, until something else is done with value1
, it is of type 'POST'
. With the type so inferred, assignment to copiedValue
is permissible.
Try initialising value1
with value false
and you will see that you get an error.
Also, if TS compiler allows value1 because it knows that this variable holds "POST" at the moment of assignment to copiedValue variable, what is a problem with value2 variable if it also holds absolutely the same "POST" value?
In the case of value2
, the added type string
means that, under the rules of the compiler, it cannot be determined whether value2
is of type 'POST'
or string
at the relevant point in the code. The compiler would not appear to be sophisticated enough to do that.
For the compiler to do that it would require it checking that no manipulation of the string contents of the value of value2
had not been done (eg to add a character to turn its value from 'POST'
into 'POSTS'
). It's easy to imagine that adding such a feature is not a priority of the TypeScript team.
CodePudding user response:
If copiedValue
is of type 'POST'
, that's the only value it can accept. You shouldn't be able to assign value1
or value2
to it as far as type is concerned.
Typescript may be smart enough to see that in this particular case, value1
is explicitly assigned the value 'POST'
and so it can safely assign it to copiedValue
regardless, but that would just be a convenience it's giving you since the value is known at compile time.
Yes I think you're right that it's not able to do that in the case of value2
because there's ambiguity there as to whether 'POST'
should be considered type 'POST'
or type string
.
Generally, typing anything 'EXPLICIT STRING HERE' | string
is going to give you these kinds of problems. I would say in (nearly?) every case, you want to enumerate all possible string values or type something as string
, but not both.