При работе с дженериками (Generics) часто возникает задача ограничить типы так, чтобы они соответствовали ключам определенного объекта. Для этого используется оператор keyof в сочетании с ключевым словом extends.
Конструкция K extends keyof T гарантирует, что тип K может быть только одним из ключей типа T. Это незаменимо при написании безопасных функций для получения или изменения свойств объектов, таких как getProperty(obj, key), где TypeScript подскажет возможные ключи и запретит опечатки.
Здесь вы научитесь связывать дженерики с ключами объектов для повышения надежности кода.
- Модуль 1: Введение в TypeScript
- Модуль 2: Примитивные типы
- Модуль 3: Специальные типы
- Модуль 4: Массивы
- Модуль 5: Кортежи (Tuples)
- Модуль 6: Объекты
- Модуль 7: Функции
- Модуль 8: Union типы
- Модуль 9: Литеральные типы
- Модуль 10: Type Aliases
- Модуль 11: Интерфейсы
- Модуль 12: Type Guards и Narrowing
- Модуль 13: Enums
- Модуль 14: Классы
- Модуль 15: Generics — основы
- Модуль 16: Generics — ограничения
- Generic Constraints (extends).
- Использование keyof с Generics.
- Значения по умолчанию для Generic.
- Модуль 17: Utility Types — базовые
- Модуль 18: Utility Types — работа с Union
- Модуль 19: Utility Types — функции
- Модуль 20: Type Assertions
- Модуль 21: Keyof и Typeof операторы
- Модуль 22: Mapped Types
- Модуль 23: Conditional Types
- Модуль 24: Discriminated Unions
- Модуль 25: Модули и типы
- Модуль 26: Declaration Files
- Модуль 27: Типизация асинхронного кода
- Модуль 28: Практические паттерны
1. Выделение ограничения
В данном задании вам представлена сигнатура обобщенной функции на TypeScript. Разметьте выделенные фрагменты кода, указав для каждого, является ли он именем функции, объявлением generic-параметра, ключевым словом ограничения, оператором keyof, ссылкой на тип или именем параметра. Обратите внимание на часть, отвечающую за ограничение дженерика ключами объекта (использование 'extends keyof').
function {{getProperty~|~t1}}<{{T~|~t2}}, {{K~|~t3}} {{extends~|~t4}} {{keyof~|~t5}} {{T~|~t6}}>({{obj~|~t7}}: {{T~|~t8}}, {{key~|~t9}}: {{K~|~t10}}): {{T~|~t11}}[{{K~|~t12}}] {
return obj[key];
}2. Связывание типа и ключей
Дополните объявление функции getValue, чтобы второй параметр key был ограничен ключами первого параметра obj. Используйте ключевые слова для ограничения generic-параметра. Функция должна возвращать значение типа, соответствующего свойству объекта по переданному ключу. Заполните пропуски в коде, чтобы обеспечить типовую безопасность при обращении к свойствам объекта.
// Функция getValue возвращает значение свойства объекта по заданному ключу.
// Второй аргумент должен быть ключом первого аргумента.
function getValue<T, K input1S input2S T>(obj: T, key: K): T[K] {
return obj[key];
}3. Валидные ключи
В данном фрагменте кода TypeScript определён интерфейс `Car` и функция `getProperty`, которая принимает объект и ключ. Внимательно изучите вызовы функции `getProperty`. Ваша задача — отметить все строковые литералы, которые являются валидными ключами интерфейса `Car` (то есть существуют в этом интерфейсе). Не отмечайте строки, которые не являются ключами `Car`, даже если они встречаются в вызовах функции. Также не отмечайте никакие другие части кода (например, имена переменных, значения свойств и т.д.).
interface Car {
brand: string;
model: string;
year: number;
}
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const myCar: Car = { brand: 'Toyota', model: 'Corolla', year: 2020 };
// Примеры вызовов функции
getProperty(myCar, {{"brand"~|~t1}});
getProperty(myCar, {{"model"~|~t2}});
getProperty(myCar, {{"year"~|~t3}});
getProperty(myCar, {{"color"~|~t4}});
getProperty(myCar, {{"price"~|~t5}});4. Типизация аргументов
В этом задании вам нужно выбрать правильную типизацию для аргумента 'key' в функции обновления поля объекта. Функция updateField принимает объект типа T, ключ и новое значение, затем обновляет соответствующее поле. Из предложенных вариантов выберите тип, который гарантирует, что ключ будет существующим свойством объекта типа T, обеспечивая типобезопасность при обращении к полям объекта.
function updateField<T>(obj: T, key: input1S, value: T[keyof T]): void {
obj[key] = value;
}
interface User {
name: string;
age: number;
}
const user: User = { name: "Alice", age: 30 };
updateField(user, "name", "Bob");5. Функция getProperty
Из предложенных строк соберите корректную сигнатуру функции getProperty на TypeScript, которая использует Generics с ограничением keyof для безопасного доступа к свойствам объекта. Функция должна принимать объект и ключ, который гарантированно является ключом этого объекта, и возвращать значение соответствующего типа. В решении должны использоваться только необходимые строки — лишние строки (decoys) включать не нужно.
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K]function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]): voidreturn obj[key];}6. Исправление ограничения
В этом фрагменте кода TypeScript, использующем дженерики и keyof, допущена синтаксическая ошибка. В объявлении функции getProperty пропущено ключевое слово 'extends' между именем дженерика и 'keyof T', из-за чего компилятор не может правильно интерпретировать ограничение типа. Исправьте строку с ошибкой, чтобы функция могла корректно получать значение свойства объекта по его ключу.
function getProperty<T, K keyof T>(obj: T, key: K): T[K] { return obj[key];} const person = { name: 'Alice', age: 30 };const nameValue = getProperty(person, 'name'); // Ожидается 'Alice'7. Результат ограничения
Рассмотрите приведенный код TypeScript, который определяет интерфейс Product и обобщенную функцию getValue с ограничением типа для параметра key. На основе понимания оператора keyof и ограничений дженериков, выберите верное утверждение о том, какие значения могут быть переданы в качестве аргумента key при вызове функции getValue для объекта laptop.
interface Product {
id: number;
name: string;
price: number;
}
function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const laptop: Product = { id: 1, name: "Laptop", price: 999 };