TypeScript
Beginner
1 min read
Generic Components, Custom Hooks, and Context
Example
import { createContext, useContext, useState, type ReactNode } from "react";
// Generic List component
interface ListProps<T> {
items: T[];
keyExtractor: (item: T) => string | number;
renderItem: (item: T) => ReactNode;
emptyMessage?: string;
}
function List<T>({ items, keyExtractor, renderItem, emptyMessage = "No items" }: ListProps<T>) {
if (items.length === 0) return <p>{emptyMessage}</p>;
return <ul>{items.map(item => <li key={keyExtractor(item)}>{renderItem(item)}</li>)}</ul>;
}
// Usage — T is inferred as { id: number; name: string }
// <List items={users} keyExtractor={u => u.id} renderItem={u => <span>{u.name}</span>} />
// Custom hook with typed tuple return
function useLocalStorage<T>(key: string, initialValue: T): [T, (val: T) => void] {
const [stored, setStored] = useState<T>(() => {
try {
const item = localStorage.getItem(key);
return item ? (JSON.parse(item) as T) : initialValue;
} catch { return initialValue; }
});
const setValue = (value: T) => {
setStored(value);
localStorage.setItem(key, JSON.stringify(value));
};
return [stored, setValue];
}
// Typed Context with null-asserting hook
interface AuthContextValue {
user: { id: number; name: string } | null;
login: (email: string, password: string) => Promise<void>;
logout: () => void;
}
const AuthContext = createContext<AuthContextValue | null>(null);
export function useAuth(): AuthContextValue {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error("useAuth must be used within <AuthProvider>");
return ctx;
}
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<AuthContextValue["user"]>(null);
const login = async (email: string, _pw: string) => { setUser({ id: 1, name: email }); };
const logout = () => setUser(null);
return <AuthContext.Provider value={{ user, login, logout }}>{children}</AuthContext.Provider>;
}
Related Resources
TypeScript Reference
Complete tag & property list
TypeScript How-To Guides
Step-by-step practical guides
TypeScript Exercises
Practice what you've learned
More in TypeScript
This is the last lesson in this section.
Create a free account to earn a certificate