Чи можна зробити generic-клас?
Що таке generic-клас
Generic-клас - це клас, у якому один або кілька типів (наприклад, T, U, K, V)
передаються як параметри, щоб зробити його гнучким і типобезпечним.
Він не прив'язаний до конкретного типу даних, а працює з будь-якими, зберігаючи строгу типізацію.
1. Найпростіший приклад
class Box<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
}Використання:
const box1 = new Box<number>(123);
const box2 = new Box<string>("Hello");
console.log(box1.getValue()); // 123
console.log(box2.getValue()); // HelloТут T - універсальний параметр:
- при створенні
Box<number>→T = number, - при створенні
Box<string>→T = string.
TypeScript стежить, щоб тип був узгоджений:
box1.getValue().toFixed(2); // OK, T = number
box2.getValue().toUpperCase(); // OK, T = string2. Generic-клас з кількома параметрами
class Pair<K, V> {
constructor(public key: K, public value: V) {}
describe() {
console.log(`Key: ${this.key}, Value: ${this.value}`);
}
}
const pair = new Pair<string, number>("age", 30);
pair.describe(); // Key: age, Value: 30Тут
K- тип ключа,V- тип значення. Можна використовувати будь-яку кількість generic-параметрів.
3. Generic-клас з обмеженням (extends)
Можна обмежити тип параметра, щоб він відповідав певній структурі:
interface Identifiable {
id: number;
}
class Repository<T extends Identifiable> {
private items: T[] = [];
add(item: T) {
this.items.push(item);
}
findById(id: number): T | undefined {
return this.items.find(i => i.id === id);
}
}
const users = new Repository<{ id: number; name: string }>();
users.add({ id: 1, name: "Tim" });
users.add({ id: 2, name: "Alex" });
console.log(users.findById(2)); // { id: 2, name: 'Alex' }Тут
Tмає бути об'єктом зid: number. Це запобігає помилкам, якщо хтось спробує додати щось безid.
4. Generic-клас з типом за умовчанням
Можна задати тип за умовчанням, якщо його не вказано при створенні:
class Storage<T = string> {
private data: T[] = [];
add(item: T) {
this.data.push(item);
}
getAll(): T[] {
return this.data;
}
}
const s1 = new Storage(); // T = string (за умовчанням)
s1.add("one");
s1.add("two");
const s2 = new Storage<number>();
s2.add(10);
s2.add(20);5. Generic-клас + інтерфейси
Інтерфейси теж можуть бути generic - і класи можуть їх реалізовувати:
interface IStorage<T> {
add(item: T): void;
getAll(): T[];
}
class ArrayStorage<T> implements IStorage<T> {
private data: T[] = [];
add(item: T) {
this.data.push(item);
}
getAll(): T[] {
return this.data;
}
}Так можна створювати "типобезпечні контейнери".
6. Generic-клас з успадкуванням
class BaseResponse<T> {
constructor(public data: T, public success: boolean) {}
}
class ApiResponse<T> extends BaseResponse<T> {
constructor(data: T, public status: number) {
super(data, status >= 200 && status < 300);
}
}
const response = new ApiResponse({ id: 1, name: "Tim" }, 200);
console.log(response.data.name); // TimДженерики можна успадковувати і передавати далі по ієрархії класів.
Підсумок
| Можливість | Приклад | Опис |
|---|---|---|
| Простий generic | class Box<T> { ... } | Типізує вміст |
| Кілька параметрів | class Pair<K, V> | Кілька типів одночасно |
| Обмеження | <T extends SomeType> | Обмежує допустимі типи |
| Тип за умовчанням | <T = string> | Якщо тип не вказано |
| Реалізація інтерфейсу | class A<T> implements I<T> | Спільно з generic-інтерфейсами |
| Успадкування | class B<T> extends A<T> | Дженерики передаються далі |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.