← Назад к вопросам
Как ограничить Generic на входящие данные?
2.0 Middle🔥 183 комментариев
#Soft Skills и рабочие процессы
Комментарии (3)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как ограничить Generic на входящие данные
Generic constraints — это способ ограничить типы, которые можно подставить в Generic параметр. Вместо того чтобы функция принимала любой тип, ты можешь требовать, чтобы тип удовлетворял определённым условиям используя ключевое слово extends.
Базовое ограничение с extends
// ❌ Без ограничения - может быть любой тип
function getProperty<T>(obj: T, key: string): any {
return obj[key]; // TypeScript ошибка: не знает есть ли key
}
// ✅ С ограничением - T должен быть объект
function getProperty<T extends object>(obj: T, key: keyof T): any {
return obj[key];
}
const user = { name: "Alice", age: 30 };
getProperty(user, "name"); // ✅ OK
getProperty(user, "email"); // ❌ Ошибка: нет такого свойства
Ограничение на интерфейс
// Только объекты с полем id
interface HasId {
id: string | number;
}
function findById<T extends HasId>(items: T[], id: string | number): T | undefined {
return items.find(item => item.id === id);
}
// ✅ User имеет id
const users = [{ id: "1", name: "Alice" }];
findById(users, "1"); // OK
// ❌ Product не имеет id
const products = [{ sku: "ABC" }];
findById(products, "ABC"); // Ошибка
Ограничение на примитивные типы
// T должен быть только string или number
function processValue<T extends string | number>(value: T): T {
return value;
}
processValue("hello"); // ✅ OK
processValue(42); // ✅ OK
processValue(true); // ❌ Ошибка
// T должен быть только массив
function getFirstElement<T extends any[]>(arr: T): T[0] {
return arr[0];
}
getFirstElement([1, 2, 3]); // ✅ OK
getFirstElement("hello"); // ❌ Ошибка
Несколько условий
// T должен быть объектом И иметь свойство email
interface User {
email: string;
}
function sendEmail<T extends User>(user: T): void {
console.log("Sending to:", user.email);
}
sendEmail({ email: "alice@example.com" }); // ✅ OK
sendEmail({ name: "Bob" }); // ❌ Ошибка: нет email
Практический пример: сортировка объектов
// T должен иметь метод compareTo
interface Comparable {
compareTo(other: Comparable): number;
}
function sort<T extends Comparable>(items: T[]): T[] {
return items.sort((a, b) => a.compareTo(b));
}
class User implements Comparable {
constructor(public name: string, public age: number) {}
compareTo(other: User): number {
return this.age - other.age;
}
}
const users = [
new User("Alice", 30),
new User("Bob", 25)
];
sort(users); // ✅ Отсортирован по возрасту
Ограничение ключами объекта (keyof)
// K должен быть ключом объекта T
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "Alice", age: 30 };
getProperty(user, "name"); // ✅ OK, возвращает string
getProperty(user, "age"); // ✅ OK, возвращает number
getProperty(user, "email"); // ❌ Ошибка
// TypeScript точно знает возвращаемый тип!
const name: string = getProperty(user, "name"); // ✅ Правильный тип
Условные типы (Conditional Types)
// Если T это массив, вернуть элемент, иначе сам T
type Flatten<T> = T extends Array<infer U> ? U : T;
type StrResult = Flatten<string[]>; // string
type NumResult = Flatten<number>; // number
// Практический пример: функция для работы с массивами и одиночными значениями
function processValue<T extends any[] | string>(value: T): T extends any[] ? T[0] : T {
if (Array.isArray(value)) {
return value[0] as any;
}
return value as any;
}
processValue(["a", "b"]); // ✅ Вернёт "a"
processValue("hello"); // ✅ Вернёт "hello"
React компонент с ограничениями
interface BaseProps {
id: string;
className?: string;
}
// Props должны расширять BaseProps
function Card<T extends BaseProps>(props: T) {
return (
<div id={props.id} className={props.className}>
Содержимое карточки
</div>
);
}
// ✅ Работает - есть id
<Card id="card-1" className="p-4" />;
// ❌ Ошибка - отсутствует обязательное поле id
<Card className="p-4" />;
Чек листо типо-безопасности
- Используй
extendsдля ограничения Generic типов - Используй
keyofдля ограничения ключами объекта - Используй
inferв условных типах для вывода типа - Всегда специфицируй ограничение если Generic может быть неправильным типом
Итог: Generic constraints делают код более безопасным, предотвращая ошибки типов на этапе разработки вместо runtime, и улучшают автодополнение в IDE.