Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Generics в TypeScript
Generics (обобщённые типы) — это механизм TypeScript для создания компонентов, функций и классов, которые работают с разными типами данных, сохраняя при этом типобезопасность. Это один из ключевых инструментов для написания переиспользуемого и гибкого кода.
Базовый пример: Generic функция
Представь функцию, которая возвращает переданный аргумент как есть:
function identity<T>(arg: T): T {
return arg;
}
const num = identity<number>(42); // num: number
const str = identity<string>("hello"); // str: string
const bool = identity(true); // bool: boolean (тип выводится автоматически)
Здесь <T> — это переменная типа (type variable). Когда мы вызываем функцию, TypeScript автоматически определяет, какой тип подставить вместо T.
Generic компонент React
В React Generics позволяют создавать переиспользуемые компоненты со строгой типизацией:
interface CardProps<T> {
data: T;
render: (item: T) => React.ReactNode;
}
function Card<T>({ data, render }: CardProps<T>) {
return (
<div className="card">
{render(data)}
</div>
);
}
// Использование
const userCard = (
<Card<User>
data={{ id: 1, name: "Alice", email: "alice@example.com" }}
render={(user) => <p>{user.name} ({user.email})</p>}
/>
);
Generic с ограничениями (Constraints)
Можно ограничить, какие типы можно подставлять. Например, функция, которая работает только с объектами, имеющими свойство length:
interface Lengthwise {
length: number;
}
function getLength<T extends Lengthwise>(arg: T): number {
return arg.length;
}
getLength([1, 2, 3]); // OK: array has length
getLength("hello"); // OK: string has length
getLength({ length: 10 }); // OK: object has length property
getLength(42); // ERROR: number has no length
Generic хук React
Кастомные хуки часто используют Generics для работы с разными типами состояния:
function useFetch<T>(url: string): { data: T | null; loading: boolean; error: Error | null } {
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((json: T) => {
setData(json);
setLoading(false);
})
.catch((err) => {
setError(err);
setLoading(false);
});
}, [url]);
return { data, loading, error };
}
// Использование
interface Post {
id: number;
title: string;
body: string;
}
const { data: posts, loading } = useFetch<Post[]>("/api/posts");
Multiple Type Parameters
Функция может иметь несколько переменных типов:
function swap<T, U>(a: T, b: U): [U, T] {
return [b, a];
}
const result = swap("hello", 42); // result: [number, string]
Generic утилиты TypeScript
TypeScript имеет встроенные Generic типы для трансформации:
// Pick — выбрать только некоторые свойства
type UserPreview = Pick<User, "id" | "name">;
// Omit — исключить свойства
type UserWithoutPassword = Omit<User, "password">;
// Partial — все свойства опциональны
type PartialUser = Partial<User>;
// Record — создать объект с определённым набором ключей
type Roles = Record<"admin" | "user" | "guest", boolean>;
const roles: Roles = { admin: true, user: false, guest: false };
Когда использовать Generics
Используй Generics когда:
- Функция/компонент работает с разными типами данных
- Нужна типобезопасность без дублирования кода
- Создаёшь переиспользуемые хуки или компоненты
- Работаешь с асинхронным кодом (Promise, async/await)
Избегай Generics когда:
- Работаешь с одним конкретным типом
- Логика специфична для одного типа данных
- Generics усложняют код без пользы
Практический пример: API response wrapper
interface ApiResponse<T> {
success: boolean;
data: T | null;
error: string | null;
}
async function fetchData<T>(url: string): Promise<ApiResponse<T>> {
try {
const response = await fetch(url);
const data = await response.json() as T;
return { success: true, data, error: null };
} catch (err) {
return {
success: false,
data: null,
error: err instanceof Error ? err.message : "Unknown error",
};
}
}
// Использование
const result = await fetchData<{ id: number; name: string }>("/api/user");
if (result.success && result.data) {
console.log(result.data.name);
}
Generics — это основа для написания чистого, безопасного и переиспользуемого кода в TypeScript. Они позволяют сохранить гибкость JavaScript, добавив при этом строгую типизацию.