React Context with TypeScript: Part 4 - Creating a context with no default and no undefined check
Tags: react, typescript
Published: 2020-03-11 04:59:45

---
title: React Context with TypeScript: Part 4 - Creating a context with no default and no undefined check
published: true
description: How to use TypeScript to create a strongly-typed React context without having to pass a default and not do any undefined checks when consuming it
tags: react,typescript
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/e9o0s3wupeiuxn3wb5ai.jpg
canonical_url: https://www.carlrippon.com/react-context-with-typescript-p4/
---

This is the final post in a series of posts on [React context](https://reactjs.org/docs/context.html) with TypeScript. In the [previous post](https://www.carlrippon.com/react-context-with-typescript-p3/), we consumed a context in a class component. In this post, we will learn how to create a context without having to pass a default and then do any `undefined` checks when consuming it.

- Part 1 - [Simple context with function components](https://www.carlrippon.com/react-context-with-typescript-p1/)
- Part 2 - [Complex context with function components](https://www.carlrippon.com/react-context-with-typescript-p2/)
- Part 3 - [Context with class components](https://www.carlrippon.com/react-context-with-typescript-p3/)
- Part 4 - [Creating a context with no default and no undefined check](https://www.carlrippon.com/react-context-with-typescript-p4/) (this post)

## The problem

The type for `createContext` requires a default value to be passed into it, but often it doesn't make sense to pass a default. So, we end up passing `undefined` as the default:

```typescript
const ThemeContext = React.createContext<
  ThemeContextType | undefined
>(undefined);
```

... and then checking for `undefined` everywhere we consume it:

```typescript
const { theme, setTheme } = useTheme()!;
```

## Creating a wrapper for creating a context

A solution is to create a wrapper around `createContext` that deals with the default and the `undefined` check:

```typescript
export function createCtx<ContextType>() {
  const ctx = React.createContext<
    ContextType | undefined
  >(undefined);
  function useCtx() {
    const c = React.useContext(ctx);
    if (!c)
      throw new Error(
        "useCtx must be inside a Provider with a value"
      );
    return c;
  }
  return [useCtx, ctx.Provider] as const;
}
```

This function first creates the context with the generic type passed into it with `undefined` as its default value.

A nested function is then defined, which wraps the `useContext` hook. A variable `c` is assigned to the return value of the `useContext` hook which is the generic type passed in or `undefined`:


![Type of c](https://dev-to-uploads.s3.amazonaws.com/i/xinz7uwhbm3h8kn8r6f8.png)

We then throw an error if `c` is falsy, which deals with the `undefined` check. This means that when `c` is returned from the nested function, it can't `undefined` and is only the generic type we passed in:

![Type of c](https://dev-to-uploads.s3.amazonaws.com/i/tpw5viy4oak3wglcdez8.png)

Notice also we use a const assertion (`as const`) on the last line to ensure TypeScript infers a tuple type rather than an array of union types.

## Creating a context

We can now use our `createCtx` function to create a context rather than React's `createContext`:

```typescript
const [useTheme, CtxProvider] = createCtx<
  ThemeContextType
>();
```

## Creating a provider

Our `createCtx` function returns a tuple, which contains a provider component in the second element (`CtxProvider`). We can the create our specific provider component containing our required state:

```jsx
export const ThemeProvider = ({
  children
}: Props) => {
  const [theme, setTheme] = React.useState(
    "white"
  );
  ...
  return (
    <CtxProvider value={{ theme, setTheme }}>
      {children}
    </CtxProvider>
  );
};
```

This can then be placed at the appropriate position in the component tree:

```jsx
export const App = () => (
  <ThemeProvider>
    <Header />
  </ThemeProvider>
);
```

## Consuming the context

Our `createCtx` also returns a hook (`useTheme`) in the tuples first element. We can use this without having to do any `undefined` checks:

```jsx
const Header = () => {
  const { theme, setTheme } = useTheme();
  return (
    <div style={{ backgroundColor: theme }}>
      <select
        value={theme}
        onChange={e =>
          setTheme(e.currentTarget.value)
        }
      >
        <option value="white">White</option>
        <option value="lightblue">Blue</option>
        <option value="lightgreen">Green</option>
      </select>
      <span>Hello!</span>
    </div>
  );
};
```

Neat!

A full working implementation is available by clicking the link below. Give it a try and change the theme value and see the background change color.

[Open full implementation](https://codesandbox.io/s/react-ts-context-no-default-8ch32?fontsize=14&hidenavigation=1&theme=dark)

## Wrap up

The `createCtx` function is a generic function that can be used to create contexts for many situations. It simplifies consuming code because checks for `undefined` are not necessary.

That concludes this series of posts on React context with TypeScript. I hope you enjoyed it!

Originally published at [https://www.carlrippon.com/react-context-with-typescript-p4/](https://www.carlrippon.com/react-context-with-typescript-p4/) on Mar 10, 2020.