The 'typeof' type guard
Consider this example:
- We have a function that prints an input to the console
- The input could be a 'string', or an 'Array of strings'
tsfunctionprintAll (text : string | string[]) {// print each partProperty 'forEach' does not exist on type 'string | string[]'. Property 'forEach' does not exist on type 'string'.2339Property 'forEach' does not exist on type 'string | string[]'. Property 'forEach' does not exist on type 'string'.text .(( forEach str : string) => {console .log (str );});}
Here typescript is warning us that forEach is available on the array string[] but not on the single string
We can fix this by checking the typeof text before proceeding:
tsfunctionprintAll (text : string | string[]) {if (typeoftext === "object") {// text must be string[] since Arrays are objects in JS// print each parttext .forEach ((str : string) => {console .log (str );});} else {// if not array, must be a string, this is narrowingconsole .log (text );}}
Let's examine this code
-
When TypeScript encounters
typeof text === "object"inside outifstatement, it understands that as a type guard. -
This process of refining types to a more specific type than originally declared is called narrowing.
When it reaches the else statement it knows by elimination that text is a string, since we already dealt with the array string[] earlier, and string is the only other type we declared as a possible input when we declared the function:
function printAll(text: string | string[]) {
The 'typeof' operator
JavaScript supports a typeof operator which can give us information about the type of a value.
It returns a string from one of the following:
"string""number""bigint""boolean""symbol""undefined""object""function"
Note:
nullandarraysare a type of object in JavaScript
We can use these values in our type guards to narrow down the possible values of an input and work with them appropriately.
Front-End Example:
Let's create an example where we handle different types of input for a width setting.
The user can provide the width either as a string with a unit (like "100px" or "50%") or as a number representing pixels.
We'll use the typeof type guard to manage these cases.
tsfunctionsetElementWidth (element :HTMLElement ,width : string | number) {if (typeofwidth === "string") {// If width is a string,// assume it's in a valid CSS format (e.g., "100px" or "50%")element .style .width =width ;} else if (typeofwidth === "number") {// If width is a number, treat it as pixelselement .style .width = `${width }px`;}}// usage:constelement =document .getElementById ("my-element")!;setElementWidth (element , "30%"); // Sets width to 30%setElementWidth (element , 100); // Sets width to 100px