The reason to cast a type

Casting is the act of taking one type and transposing it onto something else. It is dangerous and should be used seldomly. The reason casting can have side effects is that you are taking manual control of coercing a variable into another type. The type may be creating an incompatible and unexpected result. A cast is possible for any kind of variable, from a primitive to a more-complex object.

The most basic cast scenario is getting a value that is from any and to type it. The following code shows a number that is set in any and then cast to a variable of type number. You can notice two different ways to cast. One with the smaller and bigger symbol <> and one with as. The latter is the recommended way because it does not confuse code using TSX syntax, which uses the symbols for a component:

let something: any = 1;
let variable1: number;
variable1 = <number>something;
variable1 = something as number;

The previous code works because the cast went from any to number. Casting a number to a string does not work. The reason is that cast only works if you are working with a subtype. Furthermore, any is a subtype of everything, which allows casting to every type. However, the following code does not compile because variable1 is a number that is cast to a string:

let variable1: number = 1;
let variable2: string = variable1 as string;

TypeScript is also present to avoid casting between objects that miss fields. In the following code, both types cannot be cast to each other. TypeScript cannot find m2 in Type1, and the second cast cannot find m1 in the following code:

interface Type1 {
m1: number;
}

interface Type2 {
m2: string;
m3: number;
}

let t1: Type1 = { m1: 123 };
let t2: Type2 = t1 as Type2; // Property 'm2' is missing in type 'Type1'
let t3: Type2 = { m2: "2", m3: 3 };
let t4: Type1 = t2 as Type1;// Property 'm1' is missing in type 'Type2'

However, adding m1 to Type2 changes the whole situation and allows casting in both sides without any compilation errors. The reason is that Type1 is a subtype of Type2 by its structure, which is what matters in TypeScript:

interface Type1 {
m1: number;
}

interface Type2 {
m1: number;
m2: string;
m3: number;
}

let t1: Type1 = { m1: 123 };
let t2: Type2 = t1 as Type2;
let t3: Type2 = { m1: 1, m2: "2", m3: 3 };
let t4: Type1 = t2 as Type1;

What is interesting about the last code is that the last cast is useless. The reason is that Type2 has all the structure of Type1, and Type1 is a subtype of Type2. It means that they are structurally equivalent at a minimum point in their structure:

let t3: Type2 = { m1: 1, m2: "2", m3: 3 };
let t4: Type1 = t2;

The casting is required for t1 to Type2 because t1 doesn't fulfil the contract (it misses m2 and m3). The cast produces a false Type2 because m2 and m3 are not there, which means they are undefined. Type2 does not have any undefined type for these members, which makes it problematic for future usage, since TypeScript will allow m2 to use any string's function while this one is undefined. The casting comes with great responsibilities, and the tampering type will make TypeScript unable to perform safe validation.

The slippery slope is steeper when a cast is affecting an object that is any. It's hard to avoid all  any. For example, when data is crossing between systems. An Ajax request returns a JSON object, which is an inevitability, as any. The response is not typed, and to introduce the value into TypeScript, a crucial cast is performed.

A bad pattern is to cast to any and then to the desired type. This is a way to short-circuit TypeScript, finding that the cast is not a valid one. Everything can be cast to any and from any cast to everything else:

let a: number = 1;
let b: string = "2";
a = b as number; // Doesn't compile
a = b as any as number; //Shortcircuit with any
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.46.78