create-use-context
v3.0.1
Published
Type-safe useContext wrapper: sentinel default outside Provider, hook return type uses Exclude to drop the empty marker
Maintainers
Readme
create-use-context
A small helper around React useContext for context objects that use a sentinel default (EMPTY_CONTEXT_VALUE, defined in src/createUseContext.ts). The hook throws if the tree is not under a matching Provider. TypeScript types the hook’s return as your real value type only by using Exclude to drop the sentinel from the union—unlike NonNullable, which only removes null and undefined.
Installation
This package is ESM-only (import / bundlers). It does not ship CommonJS; use import or a bundler that resolves ESM.
Using pnpm:
pnpm add create-use-contextUsing npm:
npm install create-use-contextUsing Yarn:
yarn add create-use-contextUsage
Declare context as YourValue | typeof EMPTY_CONTEXT_VALUE, pass EMPTY_CONTEXT_VALUE to createContext as the default (no provider), then wrap with createUseContext. The returned hook is typed like () => YourValue: you can still use null or undefined inside YourValue if you need them; the sentinel is only for “no provider mounted.”
import {
createContext,
useState,
type Dispatch,
type ReactNode,
type SetStateAction,
} from 'react';
import { createUseContext, EMPTY_CONTEXT_VALUE } from 'create-use-context';
const INITIAL_COUNT = 0;
export interface CounterContextValue {
counter: number;
setCounter: Dispatch<SetStateAction<number>>;
}
export const CounterContext = createContext<
CounterContextValue | typeof EMPTY_CONTEXT_VALUE
>(EMPTY_CONTEXT_VALUE);
CounterContext.displayName = 'CounterContext';
export function CounterContextProvider({ children }: { children: ReactNode }) {
const [counter, setCounter] = useState(INITIAL_COUNT);
return (
<CounterContext.Provider value={{ counter, setCounter }}>
{children}
</CounterContext.Provider>
);
}
export const useCounterContext = createUseContext(CounterContext);
export function CounterApp() {
const { counter, setCounter } = useCounterContext();
return (
<button type="button" onClick={() => setCounter(counter + 1)}>
{counter} — add one
</button>
);
}
export function App() {
return (
<CounterContextProvider>
<CounterApp />
</CounterContextProvider>
);
}Development
Requires Node.js ≥ 20.19 (for the tsdown toolchain).
pnpm install
pnpm typecheck
pnpm test
pnpm build