DEV Community

Nabeel Valley
Nabeel Valley

Posted on • Originally published at nabeelvalley.co.za on

stdout: Type Guards and Narrowing in Typescript

Type guards (also known as Narrowing) allow 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

Contents

Using typeof

We can use the typeof keyword in javascript to find out what type an object is. This is useful if we have an object that can take on different structures, for example

type Data = string[]
type GetData = Data | (() => Data)

Enter fullscreen mode Exit fullscreen mode

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:

const fetchData = (getData: GetData): Data => {
  if (typeof getData === 'function') {
    return getData()
  }

  return getData
}

Enter fullscreen mode Exit fullscreen mode

Using in

Javascript also has the in operator which can be used to infer types by us checking a property of an object

type SimpleData = { 
  name:string;
}

type ComplexData = {
  name: {
    first: string;
    last: string;
  }
  isComplex: true;  
}

type AnyData = SimpleData | ComplexData
Enter fullscreen mode Exit fullscreen mode

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

const getComplexName = (data: AnyData): string => {
  // isComplex is the name of the key that we expect in `ComplexData` but not `SimpleData`
  if ('isComplex' in data) {
    return [data.name.first, data.name.last].join(' ')
  }

  return data.name
}

Enter fullscreen mode Exit fullscreen mode

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:

const isComplex = (data: AnyData): data is ComplexData => {
  return (data as ComplexData).isComplex
}

Enter fullscreen mode Exit fullscreen mode

This can be used in place of the in check in the above example like so:

const getComplexName2 = (data: AnyData): string => {
  // isComplex is the name of the key that we expect in `ComplexData` but not `SimpleData`
  if (isComplex(data)) {
    return [data.name.first, data.name.last].join(' ')
  }

  return data.name
}

Enter fullscreen mode Exit fullscreen mode

References

Top comments (0)