createTypeSafeContext.ts
/**
* Provides a way to create typesafe contexts without having to check for null
* initial values all of the time.
* @see https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/context/
*/
export default function createTypeSafeContext<A extends unknown | null>(): readonly [
() => A & (unknown | null),
React.Context<A | undefined>
] {
const ctx = createContext<A | undefined>(undefined);
function useCtx() {
const c = useContext(ctx);
if (c === undefined) {
throw new Error('useCtx must be inside a Provider with a value');
}
return c;
}
return [useCtx, ctx] as const; // 'as const' makes TypeScript infer a tuple
}Creating the Context
interface FooContextValue {
foo: string;
}
export const [useFooContext, FooContext] = createTypeSafeContext<FooContextValue>();
export const FooContextProvider = ({ children }: { children?: ReactNode }): JSX.Element => {
const [foo, setFoo] = useState<string>('');
return (
<FooContext.Provider value={{ foo }}>
{children}
</FooContext.Provider>
);
};Usage in Components
const { foo } = useApplianceContext();