Type Assertions / TypeScript Casting
Type assertions
Sometimes you will have information about the type of a value that TypeScript don't know about.
Type assertion allows you to set the type of a value and tell the compiler not to infer it.
This is when you, as a programmer, might have a better understanding of the type of a variable than what TypeScript can infer on its own.
type One = string;
type Two = string | number;
type Three = "hello";
// convert to less or more specific
let value: string = "hello";
let value_1 = value as Two; // less specific
let value_2 = value as Three; // more specific
TypeScript allows you to sign a type that is either less specific or more specific with as
keyword.
Besides the as
keyword, we can also use angle brackets <>
.
let value_3 = <One>"world";
let value_4 = <string | number>3;
But angle brackets cannot be used in TSX files.
const addOrConcat = (
a: number,
b: number,
c: "add" | "concat"
): string | number => {
if (c === "add") {
return a + b;
}
return "" + a + b;
};
let val: string = addOrConcat(2, 2, "concat") as string;
let val_1: string = <string>addOrConcat(2, 2, "concat");
When we do this, we are saying hey, ignore the warming, we know we're returning a string.
let val_2: number = addOrConcat(2, 2, "concat") as number; // No warming
Be careful! A string is returned.
You tell TypeScript that you know better than it, but you make a mistake.
Mistake can be made with assertions when you don't set them up correctly, because typescript completely believe us.
10 as string; // error
The error we got is Conversion of type 'number' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
But remember TypeScript can't always check.
// No warming
let a = 10 as unknown as string;
console.log(typeof a); // number
There are two assertions in a row. That is called double casting or force casting.
with Document Object Model
Type assertions are very useful with document object model.
const img_0 = document.querySelector("#img");
// intellisense: const img_0: Element | null
const img_1 = document.getElementById("#img");
// intellisense: const img_1: HTMLElement | null
const img = document.querySelector("img");
// intellisense: const img: HTMLImageElement | null
img.src; // red line under `img`
// error: 'img' is possibly 'null'.
We've had Element
, HTMLElement
and specific HTMLImageElement
.
const img = document.querySelector("img") as HTMLImageElement;
img.src; // No warming
So, we need to tell typescript we know better than it, we created the web page, we know there is an image element in the web page.
const img_1 = document.getElementById("#img")! as HTMLImageElement;
img_1.src; // No warming
We used a non-null assertion !
and type assertion.
const img = document.querySelector("img")!;
const next_img = <HTMLImageElement>document.querySelector("img");
img.src; // No warming
next_img.src; // No warming
<p>Copyright © <span id="year"></span></p>
const year = docuement.querySelector("#year")!;
const thisYear: string = new Data().getFullYear().toString();
year.setAttribute("datetime", thisYear);
year.textContent = thisYear;