Как ограничить Generic в TypeScript
Разбор вопроса «Как ограничить Generic в TypeScript» для Frontend Developer: что проверяет интервьюер, ключевые тезисы, практические примеры и частые ошибки.
Вопрос
Как ограничить Generic в TypeScript
Профессия
Frontend Developer
Что хочет услышать интервьюер
Интервьюер хочет услышать, что кандидат понимает, как ограничивать Generic типы для повышения безопасности типов и предсказуемости кода. Также важно показать практический пример использования.
Ключевые тезисы
- Использование ключевого слова
extendsдля ограничения Generic типами, интерфейсами или примитивами. - Пример:
<T extends string>означает, что GenericTможет быть только строкой или её подтипом. - Можно ограничивать несколькими типами через пересечение:
<T extends string & { length: number }>. - Ограничение Generic помогает избежать ошибок типизации и делает код более предсказуемым.
Подробный ответ
В TypeScript Generic (обобщённые типы) позволяют создавать гибкие и переиспользуемые компоненты, которые могут работать с различными типами данных. Однако иногда требуется ограничить диапазон типов, которые может принимать Generic, чтобы избежать ошибок и сделать код более предсказуемым. Для этого используется ключевое слово extends. Оно позволяет указать, что Generic должен быть определённого типа или удовлетворять определённым условиям. Например, <T extends string> означает, что Generic T может быть только строкой или её подтипом. Это полезно, когда функция или класс должны работать только с конкретными типами данных. Также можно использовать пересечение типов, чтобы ограничить Generic несколькими условиями одновременно. Например, <T extends string & { length: number }> означает, что T должен быть строкой и одновременно иметь свойство length. Ограничение Generic помогает избежать ошибок типизации и делает код более предсказуемым.
Практические примеры
Пример 1
Ограничение Generic строкой. function logLength<T extends string>(arg: T): void {
console.log(arg.length); } logLength('hello'); // Работает logLength(42); // Ошибка: аргумент не является строкойПример 2
Ограничение Generic объектом с определённым свойством. interface HasId { id: number;
}
function printId<T extends HasId>(obj: T): void {
console.log(obj.id); } printId({ id: 1, name: 'John' }); // Работает printId({ name: 'Jane' }); // Ошибка: объект не имеет свойства idПример 3
Ограничение Generic классом с определённым методом. class Animal { makeSound(): void {
console.log('Some sound'); }
}
function makeSound<T extends Animal>(animal: T): void { animal.makeSound(); } makeSound(new Animal()); // Работает makeSound({}); // Ошибка: объект не имеет метода makeSoundПример 4
Использование Utility типов для ограничения Generic. function updatePartial<T, K extends keyof T>(obj: T, key: K, value: T[K]): void { obj[key] = value; } updatePartial({ name: 'John', age: 30 }, 'age', 31); // Работает updatePartial({ name: 'John', age: 30 }, 'height', 180); // Ошибка: ключ 'height' не существует в объектеЧастые ошибки
- Типичная ошибка: Попытка использовать Generic без ограничений, когда это необходимо. Это может привести к ошибкам типизации, если функция или класс получают неподходящий тип данных.
- Ошибка: Неправильное использование пересечения типов. Например,
<T extends string & number>невозможно, так как тип не может быть одновременно строкой и числом.
Связанные темы
- Utility типы в TypeScript, такие как
Partial,Pick,Omitи другие. - Интерфейсы и типы в TypeScript, их различия и использование.
- Наследование и реализация интерфейсов в TypeScript.
- Работа с классами и методами в TypeScript.
Follow-up вопросы
Можно ли ограничить Generic так, чтобы он принимал только объекты с определённым свойством?
Уровень: basic
Да, можно использовать extends с интерфейсом или типом, описывающим нужное свойство. Например: <T extends { id: number }> — Generic T должен содержать свойство id типа number.
Как ограничить Generic, чтобы он работал только с классами, имеющими определённый метод?
Уровень: intermediate
Для этого используется extends с интерфейсом, описывающим метод. Например: <T extends { toString(): string }> — Generic T должен иметь метод toString, возвращающий string.
Как использовать Utility типы (например, Partial или Pick) для ограничения Generic?
Уровень: intermediate
Utility типы можно комбинировать с extends. Например: <T extends Partial<User>> — Generic T должен быть частичной версией типа User. Это полезно для валидации частичных данных.
Можно ли создать Generic, который ограничен только типами, имеющими конструктор?
Уровень: advanced
Да, с помощью new (...args: any[]) => any. Например: <T extends new (...args: any[]) => any> — Generic T должен быть конструктором. Это полезно для фабричных функций.
Как ограничить Generic так, чтобы он принимал только типы, совместимые с другим Generic?
Уровень: advanced
Можно использовать extends с другим Generic. Например: <T extends U, U> — Generic T должен быть подтипом U. Это полезно для функций, работающих с наследниками определённого типа.
Как наследуются от класса в TypeScript
Разбор вопроса «Как наследуются от класса в TypeScript» для Frontend Developer: что проверяет интервьюер, ключевые тезисы, практические примеры и частые ошибки.
Как сделать все поля в interface не обязательными без использования знака вопроса в TypeScript
Разбор вопроса «Как сделать все поля в interface не обязательными без использования знака вопроса в TypeScript» для Frontend Developer: что проверяет интервьюер, ключевые тезисы, практические примеры и частые ошибки.