Type Narrowing

Pro Members Only

This lesson is available if you have an active subscription.

Alternatively, some member might be able to gift it to you.

If you already have a subscription, you can sign in.

Professional TypeScript Masterclass Lessons

1.Introduction
free
⏱️ 1:54
2.Setup
free
⏱️ 5:44
3.Primitive Types
free
⏱️ 1:42
4.Instance Types
free
⏱️ 1:52
5.Arrays And Tuples
free
⏱️ 1:38
6.Objects
free
⏱️ 1:33
7.const declarations
free
⏱️ 1:03
8.Function Types
free
⏱️ 1:57
9.Structural Typing
free
⏱️ 2:10
10.Classes in TypeScript
free
⏱️ 1:48
11.Target Compiler Option
free
⏱️ 2:37
12.Generics
⏱️ 3:02
13.Special Types any And unknown
⏱️ 2:00
14.JavaScript to TypeScript
⏱️ 1:32
15.Frontend Projects
⏱️ 3:49
16.Type Assertions
⏱️ 2:15
17.Type Casting
⏱️ 1:16
18.Modules
⏱️ 1:55
19.Type Declarations
⏱️ 4:25
20.Creating NPM packages
⏱️ 3:20
21.Async Await
⏱️ 3:05
22.Running in NodeJS
⏱️ 1:40
23.Lexical this
⏱️ 2:34
24.readonly Modifier
⏱️ 1:59
25.Union Types
⏱️ 2:57
26.Literal Types
⏱️ 2:58
27.Type Narrowing
⏱️ 4:19
28.Discriminated Unions
⏱️ 3:29
29.Class Parameter Properties
⏱️ 1:02
30.Strict Compiler Option
⏱️ 6:18
31.null vs undefined
⏱️ 4:19
32.Intersection Types
⏱️ 2:03
33.Optional Modifier
⏱️ 2:47
34.Non Null Assertion Operator
⏱️ 3:40
35.Interfaces
⏱️ 2:28
36.Interface Declaration Merging
⏱️ 1:01
37.Types vs Interfaces
⏱️ 2:16
38.never Type
⏱️ 3:00
39.implements Keyword
⏱️ 1:25
40.Definite Assignment Assertion
⏱️ 2:31
41.User Defined Type Guards
⏱️ 2:02
42.Assertion Functions
⏱️ 3:42
43.Function Overloading
⏱️ 4:15
44.Call Signatures
⏱️ 2:53
45.Abstract Classes
⏱️ 1:53
46.Index Signatures
⏱️ 3:08
47.Readonly Arrays and Tuples
⏱️ 2:58
48.Double Assertions
⏱️ 2:20
49.const Assertions
⏱️ 3:55
50.this Parameter
⏱️ 2:33
51.Generic Constraints
⏱️ 2:43
52.typeof Type Operator
⏱️ 2:12
53.Lookup Types
⏱️ 3:12
54.keyof Type Operator
⏱️ 3:55
55.Conditional Types
⏱️ 4:39
56.Contitional Types with Unions and never
⏱️ 3:32
57.infer Keyword and `ReturnType<T>`
⏱️ 3:47
58.Mapped Types
⏱️ 2:48
59.Mapped Type Modifiers
⏱️ 3:37
60.Template Literal Type
⏱️ 4:28
61.Partial<T>
⏱️ 1:27
62.Required<T>
⏱️ 1:36
63.Readonly<T>
⏱️ 1:34
64.Record<K, T>
⏱️ 4:05
65.Project References
⏱️ 4:18
66.undefined vs. optional
⏱️ 2:48
67.satisfies Operator
⏱️ 2:42
68.PropertyKey Type
⏱️ 0:57
69.ThisType<T>
⏱️ 4:11
70.Awaited<T>
⏱️ 4:12
71.String Manipulation Types
⏱️ 3:36
72.Mapped Types as Clauses
⏱️ 4:01
73.Union vs Intersection Mental Model
⏱️ 3:36
74.Enums are Bad
⏱️ 8:11

Type Narrowing

Subscription Required

You must have an active subscription to access this content.
If you already have a subscription, you can sign in.

Using typeof

function padLeft(value: string, padding: number | string) {
if (typeof padding === 'number') {
return Array(padding + 1).join(' ') + value;
}
if (typeof padding === 'string') {
return padding + value;
}
throw new Error(`Expected number or string, got '${padding}'.`);
}

padLeft('Hello world', 4); // ' Hello world'
padLeft('Hello world', ' '); // ' Hello world'
padLeft('Hello world', '---'); // '---Hello world'

Using instanceof

class Cat {
meow() {
console.log('meow');
}
}

class Dog {
bark() {
console.log('woof');
}
}

type Animal = Cat | Dog;

function speak(animal: Animal) {
if (animal instanceof Cat) {
animal.meow();
}
if (animal instanceof Dog) {
animal.bark();
}
}

speak(new Cat());
speak(new Dog());

Using in

type Square = {
size: number,
};

type Rectangle = {
width: number,
height: number,
};

type Shape = Square | Rectangle;

function area(shape: Shape) {
if ('size' in shape) {
return shape.size * shape.size;
}
if ('width' in shape) {
return shape.width * shape.height;
}
}

area({ size: 2 }); // 4
area({ width: 2, height: 3 }); // 6
javascript
typescript
react
playwright

Enjoy free content straight from your inbox 💌

No spam, unsubscribe at any time.

Transcript

00:00

This is the pad left function that we previously saw in our lesson on union types. Now, the padding parameter for this function can be a string or a number allowing us to pad with a number of spaces or any given string. Now, within the function body, we are using the JavaScript type of operator to determine if the padding is a number or a string. Outside of these conditional blocks, the padding parameter can be a number or a string. Now, within these conditional blocks, TypeScript understands that if this condition is true,

00:34

when within the condition body, the padding parameter must be a number. And if you hover over the padding parameter, you can see that it is inferred to be a number within this block. The same is true for the other block. If the type of padding is a string and within the conditional block, the padding parameter will be narrowed down to the string type. Now, the JavaScript type of operator is one of the ways in which you can narrow down a union type into one of its primitive members. Now, this is perfectly fine if the union type

01:07

that you are looking at consists of primitive members like number or string. For anything else that is not a JavaScript primitive type, the type of operator actually returns the string object and therefore cannot be used to discriminate between the members. Now let's look at how we can narrow between instances of different JavaScript classes. With an example here we have a simple JavaScript class called CAT with a single method called Meow. We also have another Java strip class called dog with a single method called bark. We can capture instances of a cat

01:41

or a dog in a single type union called animal. Now we want to create this utility method called speak, which can accept any animal, and if it is a cat, it should meow, and if it is a dog, it should bark. Now, as mentioned before, we cannot use the type of operator because it'll be the string object for instances of either a cat or a dog. Now, the proper way to determine if a given object is an instance of a class is using the JavaScript instance of operator. So we check if the past in animal is an instance of a cat,

02:14

and if so, we invoke the method male. Otherwise, if it is an instance of a dog, we invoke the method bark. Now, just like the type of operator, TypeScript understands the instance of operator and understands that if this condition is true, then within the condition body animal will be a cat. And similarly, if the second condition is true, then the animal will be a dog. Now that's it for classes, but what about objects that are not created by calling a constructor of a particular class? Let's discuss those with another example. Here we have a type representing a square

02:49

with a single member called size to represent the squares width as well as its height. Then we have this type called rectangle with separate members to represent the rectangles Width and height. Now we can capture instances of a square or a rectangle in a single type union called shape. This allows us to create a utility function called area that can operate on any given shape. So if you pass in a square with a single size value of two, it should return the area four, and if you pass in a rectangle with a width of two and a height of three, it should return the area

03:22

of the rectangle, which would be six. Now, as you mentioned before, the type of operator for both of these objects would be the string object and would not help us differentiate between a square and a rectangle. Additionally, since these instances are not created by classes, we cannot use the JavaScript instance of operator to differentiate between the two objects. Fortunately, we can use the JavaScript in operator to determine if a particular property exists on the past and object and types. Script will automatically infer that if this property is present on the object,

03:55

then it must be of that particular type. So if the size property is found on the shape and this condition turns out to be true, TypeScript infers that shape must be a square. Similarly, if the width property is found on the past and shape, TypeScript infers, that shape must be a rectangle and will allow us to use the width and the height property with complete compile time type safety.

Professional TypeScript Masterclass

Professional TypeScript Masterclass

1.Introduction
free
⏱️ 1:54
2.Setup
free
⏱️ 5:44
3.Primitive Types
free
⏱️ 1:42
4.Instance Types
free
⏱️ 1:52
5.Arrays And Tuples
free
⏱️ 1:38
6.Objects
free
⏱️ 1:33
7.const declarations
free
⏱️ 1:03
8.Function Types
free
⏱️ 1:57
9.Structural Typing
free
⏱️ 2:10
10.Classes in TypeScript
free
⏱️ 1:48
11.Target Compiler Option
free
⏱️ 2:37
12.Generics
⏱️ 3:02
13.Special Types any And unknown
⏱️ 2:00
14.JavaScript to TypeScript
⏱️ 1:32
15.Frontend Projects
⏱️ 3:49
16.Type Assertions
⏱️ 2:15
17.Type Casting
⏱️ 1:16
18.Modules
⏱️ 1:55
19.Type Declarations
⏱️ 4:25
20.Creating NPM packages
⏱️ 3:20
21.Async Await
⏱️ 3:05
22.Running in NodeJS
⏱️ 1:40
23.Lexical this
⏱️ 2:34
24.readonly Modifier
⏱️ 1:59
25.Union Types
⏱️ 2:57
26.Literal Types
⏱️ 2:58
27.Type Narrowing
⏱️ 4:19
28.Discriminated Unions
⏱️ 3:29
29.Class Parameter Properties
⏱️ 1:02
30.Strict Compiler Option
⏱️ 6:18
31.null vs undefined
⏱️ 4:19
32.Intersection Types
⏱️ 2:03
33.Optional Modifier
⏱️ 2:47
34.Non Null Assertion Operator
⏱️ 3:40
35.Interfaces
⏱️ 2:28
36.Interface Declaration Merging
⏱️ 1:01
37.Types vs Interfaces
⏱️ 2:16
38.never Type
⏱️ 3:00
39.implements Keyword
⏱️ 1:25
40.Definite Assignment Assertion
⏱️ 2:31
41.User Defined Type Guards
⏱️ 2:02
42.Assertion Functions
⏱️ 3:42
43.Function Overloading
⏱️ 4:15
44.Call Signatures
⏱️ 2:53
45.Abstract Classes
⏱️ 1:53
46.Index Signatures
⏱️ 3:08
47.Readonly Arrays and Tuples
⏱️ 2:58
48.Double Assertions
⏱️ 2:20
49.const Assertions
⏱️ 3:55
50.this Parameter
⏱️ 2:33
51.Generic Constraints
⏱️ 2:43
52.typeof Type Operator
⏱️ 2:12
53.Lookup Types
⏱️ 3:12
54.keyof Type Operator
⏱️ 3:55
55.Conditional Types
⏱️ 4:39
56.Contitional Types with Unions and never
⏱️ 3:32
57.infer Keyword and `ReturnType<T>`
⏱️ 3:47
58.Mapped Types
⏱️ 2:48
59.Mapped Type Modifiers
⏱️ 3:37
60.Template Literal Type
⏱️ 4:28
61.Partial<T>
⏱️ 1:27
62.Required<T>
⏱️ 1:36
63.Readonly<T>
⏱️ 1:34
64.Record<K, T>
⏱️ 4:05
65.Project References
⏱️ 4:18
66.undefined vs. optional
⏱️ 2:48
67.satisfies Operator
⏱️ 2:42
68.PropertyKey Type
⏱️ 0:57
69.ThisType<T>
⏱️ 4:11
70.Awaited<T>
⏱️ 4:12
71.String Manipulation Types
⏱️ 3:36
72.Mapped Types as Clauses
⏱️ 4:01
73.Union vs Intersection Mental Model
⏱️ 3:36
74.Enums are Bad
⏱️ 8:11