npx create-react-app my-app --template typescript
cd my-app
yarn start
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"jsx": "react-jsx",
"module": "ESNext",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src"]
}
import React from 'react';
interface Props {
name: string;
age?: number;
}
const User: React.FC<Props> = ({ name, age }) => {
return (
<div>
<h1>{name}</h1>
{age && <p>年龄: {age}</p>}
</div>
);
};
interface UserProps {
name: string;
age?: number;
onUpdate?: (name: string) => void;
}
function User({ name, age, onUpdate }: UserProps) {
return (
<div>
<h1>{name}</h1>
{age && <p>年龄: {age}</p>}
{onUpdate && <button onClick={() => onUpdate(name)}>更新</button>}
</div>
);
}
interface ButtonProps {
text: string;
onClick: () => void;
disabled?: boolean;
variant?: 'primary' | 'secondary' | 'danger';
}
interface CardProps {
title: string;
children: React.ReactNode;
}
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label: string;
error?: string;
}
function Input({ label, error, ...rest }: InputProps) {
return (
<div>
<label>{label}</label>
<input {...rest} />
{error && <span>{error}</span>}
</div>
);
}
interface ListProps<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
}
function List<T>({ items, renderItem }: ListProps<T>) {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{renderItem(item)}</li>
))}
</ul>
);
}
const [count, setCount] = useState(0);
const [name, setName] = useState('');
const [count, setCount] = useState<number>(0);
interface User {
id: number;
name: string;
email: string;
}
const [user, setUser] = useState<User | null>(null);
const [users, setUsers] = useState<User[]>([]);
type Status = 'idle' | 'loading' | 'success' | 'error';
const [status, setStatus] = useState<Status>('idle');
const inputRef = useRef<HTMLInputElement>(null);
const divRef = useRef<HTMLDivElement>(null);
const buttonRef = useRef<HTMLButtonElement>(null);
useEffect(() => {
inputRef.current?.focus();
}, []);
const intervalRef = useRef<number | null>(null);
useEffect(() => {
intervalRef.current = window.setInterval(() => {
console.log('tick');
}, 1000);
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, []);
interface AuthContextType {
user: User | null;
login: (email: string, password: string) => Promise<void>;
logout: () => void;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within AuthProvider');
}
return context;
}
interface State {
count: number;
error: string | null;
}
type Action =
| { type: 'increment' }
| { type: 'decrement' }
| { type: 'set'; payload: number };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'increment':
return { ...state, count: state.count + 1 };
case 'decrement':
return { ...state, count: state.count - 1 };
case 'set':
return { ...state, count: action.payload };
}
}
const [state, dispatch] = useReducer(reducer, { count: 0, error: null });
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
console.log(e.currentTarget);
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value);
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
console.log('Enter pressed');
}
};
interface UseFetchResult<T> {
data: T | null;
loading: boolean;
error: Error | null;
}
function useFetch<T>(url: string): UseFetchResult<T> {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [url]);
return { data, loading, error };
}
interface User {
id: number;
name: string;
}
const { data: users } = useFetch<User[]>('/api/users');
interface FormData {
username: string;
email: string;
password: string;
}
interface FormErrors {
username?: string;
email?: string;
password?: string;
}
function RegisterForm() {
const [formData, setFormData] = useState<FormData>({
username: '',
email: '',
password: ''
});
const [errors, setErrors] = useState<FormErrors>({});
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log(formData);
};
return (
<form onSubmit={handleSubmit}>
<input
name="username"
value={formData.username}
onChange={handleChange}
/>
{errors.username && <span>{errors.username}</span>}
</form>
);
}
interface Todo {
id: number;
text: string;
completed: boolean;
}
function TodoApp() {
const [todos, setTodos] = useState<Todo[]>([]);
const [input, setInput] = useState('');
const addTodo = () => {
if (input.trim()) {
setTodos([...todos, {
id: Date.now(),
text: input,
completed: false
}]);
setInput('');
}
};
const toggleTodo = (id: number) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
return (
<div>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={addTodo}>添加</button>
<ul>
{todos.map(todo => (
<li key={todo.id} onClick={() => toggleTodo(todo.id)}>
{todo.text}
</li>
))}
</ul>
</div>
);
}