Welcome back to the TypeScript Type Guards series! You’re entering the realms of next level knowledge, woohoo!
For reference, the 4 articles in this TypeScript series:
- Understanding TypeScript: typeof Type Guard
- Understanding TypeScript: instanceof Type Guard
- Understanding TypeScript: User defined Type Guards
- TypeScript’s Literal Type Guards and “in” Operator (you’re here!)
Enjoying the series? Come and master the whole TypeScript language with us across 2 courses, beginner concepts and finally advanced. Full of real-world examples, it’ll answer so many questions you have and will have. Click here to check out more of what you’ll learn with us!
In this post we are going to learn about Literal Type Guards and then we will learn how to use the in
operator.
Table of contents
The in operator
The in
operator is very interesting, it gives us the ability to say const exists =
and then we could test something.
const exists = 'localStorage' in window;
If we run this in the browser this would result to true
for browsers that have this 'localStorage'
property on the window
object. What it’s essentially saying is does the window object have a property called 'localStorage'
. This is different to window.localStorage
because this is looking up the value whereas the in window
, and we’re checking this 'localStorage'
as a string, is checking whether the property even exists. It doesn’t care about the value, the value could be false
and this would result to true.
Free eBook
Directives, simple right? Wrong! On the outside they look simple, but even skilled Angular devs haven’t grasped every concept in this eBook.
- Observables and Async Pipe
- Identity Checking and Performance
- Web Components <ng-template> syntax
- <ng-container> and Observable Composition
- Advanced Rendering Patterns
- Setters and Getters for Styles and Class Bindings
This is a brief introduction to the in
operator, you’ll also see this with something like a for
loop. Dos prop
exist in object
, if so we want to iterate it with a for
loop.
for(const prop in object){}
Now let’s apply this to the code below.
class Song {
constructor(public title: string, public duration: number) {}
}
class Playlist {
constructor(public name: string, public songs: Song[]) {}
}
function isSong(item: any): item is Song {
return item instanceof Song;
}
function getItemName(item: Song | Playlist) {
if(item instanceof Song) {
return item.title;
}
return item.name;
}
On our isSong()
function we could return item
. But before doing so we want to check if the title
exists in our item
. Now the item
gets passed through, it could be a Song
or it could be a Playlist
.
function isSong(item: any): item is Song {
return 'title' in item;
}
It is important to remember that 'title' in item;
returns a boolean of whether the property exists or not. If the item
in the title
is available then we know that we are dealing with a Song
.
Literal Types
In TypeScript we can create Literal Types, this means that the type is in fact a literal. If we did something like const foo = 'bar';
, by default this would have a literal type of bar. We could change this by adding a type string const foo: string = 'bar';
. So we have changed the type by manually typing this for ourselves.
Let’s now demonstrate this on the code above. If we take our Song
class, even though this could be done on a type, object, interface. We are going to say that the kind
here is of type 'song'
. If we were to hover over this in our IDE we would see Song.kind: "song"
so it’s a string literal.
class Song {
kind: 'song';
constructor(public title: string, public duration: number) {}
}
Similarly we can say we are having just a 'playlist'
.
class Playlist {
kind: 'playlist';
constructor(public name: string, public songs: Song[]) {}
}
We can now go ahead and refactor the getItemName
function. So instead of saying if it is a song and say if the kind of item equals a 'song'
. Everything will be perfectly implied for because we are using structural typing with TypeScript.
function getItemName(item: Song | Playlist) {
if(item.kind === 'song') {
return item.title;
}
return item.name;
}
We have now learned how to use a literal type and we can use another Type Guard when we use that title
and then in
the item is our isSong
function. The literal type is just another way we can detect a particular property or a type of something and then we can infer that type and that’s the key to remembering: we infer those types inside those conditional blocks such as an if
statement.