Skip to main content

Як типізувати useCallback()?

Базовий синтаксис

javascript
const callback = useCallback(() => { // ... }, []);

useCallback повертає мемоізовану функцію, тип якої залежить від її тіла. TypeScript автоматично виведе тип, якщо все оголошено явно.


1. Найпростіший варіант - автотипізація (рекомендується)

TypeScript сам виводить тип функції, якщо параметри і значення, що повертається, вказані всередині:

javascript
const handleClick = useCallback((id: number) => { console.log(id); }, []);

Тип тут:

javascript
(id: number) => void

Рекомендація: не дублюй типізацію зовні, якщо TypeScript може вивести її сам.


2. Вказання типу явно (наприклад, для колбеків у props)

Іноді потрібно, щоб сигнатура колбека збігалася з очікуваним типом з пропсів або інтерфейсу.

javascript
type OnSelect = (id: string) => void; const handleSelect: OnSelect = useCallback((id) => { console.log(id); }, []);

Або, щоб не писати зайвого:

javascript
const handleSelect = useCallback<OnSelect>((id) => { console.log(id); }, []);

Вказуємо generic <OnSelect> прямо у useCallback. Це змусить TypeScript строго перевіряти сигнатуру функції.


3. Повна типізація сигнатури всередині useCallback

Якщо хочеш все явно в одному місці:

javascript
const handleChange = useCallback<(event: React.ChangeEvent<HTMLInputElement>) => void>( (event) => { console.log(event.target.value); }, [] );

Тепер handleChange буде строго типізований як ChangeEventHandler<HTMLInputElement>.


4. Приклад зі значенням, що повертається

javascript
const compute = useCallback((a: number, b: number): number => { return a + b; }, []);

Тип:

javascript
(a: number, b: number) => number

TypeScript виведе тип автоматично - явно вказувати useCallback<number> не потрібно.


5. Типізація в парі з React.FC або пропсами

Припустимо, у нас компонент, який приймає колбек у пропсах:

javascript
type Props = { onSave: (data: string) => void; }; function Form({ onSave }: Props) { const handleSubmit = useCallback(() => { onSave('data'); }, [onSave]); return <button onClick={handleSubmit}>Save</button>; }

Тут handleSubmit виведе тип (event: React.MouseEvent<HTMLButtonElement>) => void автоматично, якщо ви передасте його в onClick.


6. Використання з event-хендлерами

React вже надає типи для подій:

javascript
const handleChange = useCallback( (e: React.ChangeEvent<HTMLInputElement>) => { console.log(e.target.value); }, [] );

або з generic-підходом:

javascript
const handleClick = useCallback<React.MouseEventHandler<HTMLButtonElement>>( (e) => { e.preventDefault(); }, [] );

React.MouseEventHandler<T> = (event: React.MouseEvent<T, MouseEvent>) => void


7. Якщо потрібно типізувати generic-функцію

javascript
const identity = useCallback(<T,>(value: T): T => { return value; }, []);

Використання:

javascript
identity(123); // number identity('hello'); // string

Generic зберігається - useCallback коректно працює з <T,>.


8. Спільне використання з useMemo

Якщо useCallback повертає складну функцію, можна явно типізувати її сигнатуру і передати в мемоізацію:

javascript
type FetchFn = (url: string) => Promise<Response>; const fetchData = useCallback<FetchFn>(async (url) => { const res = await fetch(url); return res; }, []);

9. Часті помилки

Помилка 1: не вказувати залежності

javascript
const handle = useCallback(() => console.log(value), []);

Якщо value змінюється - функція буде "зависати" на старому значенні. Виправ:

javascript
const handle = useCallback(() => console.log(value), [value]);

Помилка 2: неправильний generic-порядок

javascript
useCallback<void, [string]>((value) => {}, []); // так не працює

Такий синтаксис не працює. useCallback приймає один generic - тип функції цілком:

javascript
useCallback<(value: string) => void>((value) => {}, []);

Підсумок

СценарійЯк типізувати
Проста функціяАвтоматично (TS сам виведе)
Визначена сигнатураuseCallback<FnType>(...)
Callback з пропсівconst cb: Props["onChange"] = useCallback(...)
Події ReactuseCallback<React.ChangeEventHandler<HTMLInputElement>>
Generic функціяuseCallback<<T,>(x: T) => T>

Рекомендації

  • Не типізуй вручну, якщо TypeScript може вивести тип.
  • Якщо тип важливий для сумісності з пропсами - використовуй generic у useCallback<>().
  • Для подій - використовуй вбудовані типи з React.*EventHandler.
  • Для generic-функцій - не забувай про кому <T,>.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.