Type Narrowing in Typescript
31 May 2022
Updated: 03 September 2023
Type Narrowing allows us create conditions under which an object of one type can be used as if it is of another type. We usually use this in conjunction with union types to allow us to specify different handling of the types based on the resulting value
Using typeof
We can use the typeof
keyword in javascript to find out whether what type an object is. This is useful if we have an object that can take on different structures, for example
1type Data = string[]2type GetData = Data | (() => Data)
In the above example, we have a type called GetData
which can be either some data or a function to get data. Using this, we can can create a function which fetches data like so:
1const fetchData = (getData: GetData): Data => {2 if (typeof getData === 'function') {3 return getData()4 }5
6 return getData7}
Using in
Javascript also has the in
operator which can be used to infer types by us checking a property of an object
1type SimpleData = {2 name: string3}4
5type ComplexData = {6 name: {7 first: string8 last: string9 }10 isComplex: true11}12
13type AnyData = SimpleData | ComplexData
We can then use the in
operator to check the existence of a property of an object by using it along with a key that we expect to be in one object but not another
1const getComplexName = (data: AnyData): string => {2 // isComplex is the name of the key that we expect in `ComplexData` but not `SimpleData`3 if ('isComplex' in data) {4 return [data.name.first, data.name.last].join(' ')5 }6
7 return data.name8}
Using is
We can use the typescript is
keyword to specify that the return of a boolean means that a variable satisfies a specific condition
For example, we can create a function that basically does what the in
operator in the above function does:
1const isComplex = (data: AnyData): data is ComplexData => {2 return (data as ComplexData).isComplex3}
This can be used in place of the in
check in the above example like so:
1const getComplexName2 = (data: AnyData): string => {2 // isComplex is the name of the key that we expect in `ComplexData` but not `SimpleData`3 if (isComplex(data)) {4 return [data.name.first, data.name.last].join(' ')5 }6
7 return data.name8}