Reputation: 4601
Is it true that TypeScript allows us to override its inferred and analyzed view of types in any way we want to?
Consider the following simple example please
let myAge: number;
myAge = window.prompt('age?');
// we cannot do this because window.prompt returns a string
// so we need a type assertion, but the 2 ways I know does not cut it
let myAgeStr: string;
myAgeStr = window.prompt('age?');
// method 1
myAge = myAgeStr as number; // fails
// method 2
myAge = <number> myAgeStr; // also fails
Fails
means Type 'string' is not assignable to type 'number'
.
What do we do then?
Upvotes: 4
Views: 3333
Reputation: 328302
TL;DR you can do it but you probably don't want to. Parse the string as a number.
Type assertions from one type to another are only allowed when at least one of the types is assignable to the other. There's the safe "up casting" direction, where a you widen a value to a supertype (throwing away information):
// safe
let h = "hello" as (string | number); // widening string to string|number
And there's the unsafe "down casting" direction, where you narrow a value to a subtype (adding information the compiler can't verify):
// unsafe but correct
let okay = h as "hello"; // narrowed string|number to string literal "hello"
// unsafe and incorrect
let notOkay = h as "goodbye"; // narrowed string|number to string literal "goodbye".
But what you can't do is do type assertions between two unrelated types, where neither one is assignable to the other:
let s = "string";
s as number; // error
let n = 1;
n as string; // error
Enter any
, the escape hatch from the type system. The type any
is considered assignable to and from every other type. If you really want to assert a value is an unrelated type, you can use any
as an intermediary. This is quite unsafe, of course:
n = s as any as number; // you're the boss
s = n as any as string; // you're the boss
So you can do it:
myAge = window.prompt('age?') as any as number; // bad idea
But please don't do it. TypeScript is warning you, correctly, that a string
is not a number
. Sure, lots of JavaScript functions will coerce a string to a number if that's what they expect, but lots of JavaScript functions won't do that:
n = "3" as any as number;
console.log(n + 5); // 35, not 8!
So it's really a bad idea to force TypeScript to allow you to do foolish things. If you want to interpret a string as a number, parse it:
let myAge: number;
myAge = Number(window.prompt('age?')); // always a number, may be NaN
The Number
function will always return a number
, and TypeScript knows this, and now both you and TypeScript are happy, both at compile time and runtime. Do keep in mind that NaN
is a number
and that's what you'll get if you do something like Number("hello")
. So after getting myAge
as a number
, you probably want to check it via isNaN()
before doing anything numeric with it.
Hope that helps; good luck!
Upvotes: 8