← Back to TypeScript Course | Chapter 14: TypeScript with React | Lesson 7 of 8

Typing Context API

The Context API lets components share values without passing props through every level. TypeScript can describe the context value so consumers and providers use the same contract.

Creating a Typed Context

Creating a typed context means passing an interface as createContext's generic argument, so every consumer of that context automatically gets the correct shape without re-declaring the type at each use.

Example: Creating a Typed Context

typescript
import React, { createContext } from "react";

interface ThemeContextValue {
	theme: "light" | "dark";
}

const ThemeContext = createContext<ThemeContextValue>({ theme: "light" });

export default ThemeContext;

Using useContext

useContext returns whatever type the context was created with, so once the context itself is typed correctly, using it anywhere in the tree requires no extra type annotations at the call site.

Example: Using useContext

typescript
import React, { createContext, useContext } from "react";

const ThemeContext = createContext({ theme: "light" });

function ThemedText(): React.JSX.Element {
	const { theme } = useContext(ThemeContext);
	return <p>Theme: {theme}</p>;
}

export default ThemedText;

Context with State

Combining context with state means typing the context's value as an object holding both the current state and its setter function, letting consumers both read and update shared state with full type safety.

Example: Context with State

typescript
import React, { createContext, useState } from "react";

interface CountContextValue {
	count: number;
	setCount: (n: number) => void;
}

const CountContext = createContext<CountContextValue | undefined>(undefined);

export default CountContext;

Creating a Safe Context Hook

A safe context hook wraps useContext in a custom hook that throws if the context is accessed outside its provider, converting a possibly-undefined context value into a guaranteed non-null type for consumers.

Example: Creating a Safe Context Hook

typescript
import React, { createContext, useContext } from "react";

const CountContext = createContext<{ count: number } | undefined>(undefined);

function useCount() {
	const ctx = useContext(CountContext);
	if (!ctx) throw new Error("useCount must be used within CountContext.Provider");
	return ctx;
}

export default useCount;

Context with Complex Values

Context holding complex, deeply nested values benefits from breaking the value's interface into smaller named types, keeping the context's overall type readable instead of one large inline object type.

Example: Context with Complex Values

typescript
import React, { createContext } from "react";

interface User {
	name: string;
}
interface AppContextValue {
	user: User | null;
	permissions: string[];
}

const AppContext = createContext<AppContextValue>({ user: null, permissions: [] });

export default AppContext;
🔒

Chapter Quiz — Complete all 8 topics to unlock

0/8 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.