Vấn đề thường gặp là gõ any cho event hoặc đoán sai kiểu element.
Event handlers — React có sẵn type generic theo element và loại event. Lấy đúng kiểu thay vì any:
const onClick = (e: React.MouseEvent<HTMLButtonElement>) => {}
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value) // value được type đúng
}
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => e.preventDefault()Mẹo: khai báo handler inline trên JSX prop thì TS tự suy ra type của e — chỉ cần annotate khi tách hàm ra ngoài.
Refs — type theo element được gắn, khởi tạo null:
const inputRef = useRef<HTMLInputElement>(null)
// inputRef.current là HTMLInputElement | null → phải guard
inputRef.current?.focus()Lưu ý: useRef<T>(null) cho ref DOM tạo ra ref read-only (RefObject), đúng cho việc gắn vào JSX.
- Còn
useRef<T>(initial)cho "instance variable" mutable thì khởi tạo bằng giá trị thật, không phảinull. - Phân biệt hai cái này để tránh lỗi type "current is read-only".
The common pitfall is typing the event as any or guessing the element type wrong.
Event handlers — React ships generic types keyed by element and event kind. Use them instead of any:
const onClick = (e: React.MouseEvent<HTMLButtonElement>) => {}
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value) // value is typed
}
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => e.preventDefault()Tip: declaring the handler inline on the JSX prop lets TS infer e's type — you only annotate when extracting the function.
Refs — type by the attached element, initialized to null:
const inputRef = useRef<HTMLInputElement>(null)
// inputRef.current is HTMLInputElement | null → must guard
inputRef.current?.focus()Note: useRef<T>(null) for a DOM ref produces a read-only ref (RefObject), correct for attaching to JSX. useRef<T>(initial) for a mutable "instance variable" should be initialized with a real value, not null.
Distinguishing the two avoids the "current is read-only" type error.