Məzmuna keç
Educora
İrəli18 dəq7 / 8

Generiklər və köməkçi tiplər

Tip parametrləri ilə istənilən tiplə işləyən, amma tip məlumatını itirməyən funksiyalar və interfeyslər yaz, onları `extends` və `keyof` ilə məhdudlaşdır, `Partial`, `Pick`, `Omit`, `Record` və `ReturnType` ilə yeni tiplər düzəlt.

Özünü yoxla
Bu dərsdə öyrənəcəksən
  • <T> tip parametri olan generik funksiya yazmaq
  • Generik interfeys və tiplər təsvir etmək
  • Tip parametrlərini extends və keyof ilə məhdudlaşdırmaq
  • Partial, Pick, Omit, Record və ReturnType köməkçi tiplərini tətbiq etmək

Massivin ilk elementini qaytaran funksiya lazımdır: şəhərlər üçün, qiymətlər üçün, istifadəçilər üçün. Hər tip üçün ayrıca firstString, firstNumber, firstUser yazmaq mənasızdır. any isə tip məlumatını məhv edir. Aşağıdakı kod səhvsiz kompilyasiya olunur, amma işə düşəndə TypeError: city.toFixed is not a function xətası ilə çökür — kompilyator city-nin sətir olduğunu artıq bilmir:

TypeScript
function firstAny(items: any[]): any {
  return items[0];
}

const city = firstAny(['Baku', 'Ganja']);
console.log(city.toFixed(2));

Generik funksiyalar

Tərif
Generik (ümumiləşdirilmiş tip)

Tipi parametr kimi qəbul edən funksiya, interfeys və ya sinif. Tip parametri bucaq mötərizəsində yazılır — adətən <T> — və çağırış zamanı konkret tiplə əvəz olunur, necə ki adi parametr konkret qiymətlə əvəz olunur.

TypeScript
function first<T>(items: T[]): T | undefined {
  return items[0];
}

const city = first(['Baku', 'Ganja']);
const score = first([90, 75]);
const empty = first<boolean>([]);

console.log(city?.toUpperCase(), score?.toFixed(1), empty);
Gözlənilən nəticə
BAKU 90.0 undefined
city-nin tipi string | undefined, score-un tipi number | undefined-dır. Massiv boş ola bildiyi üçün undefined də nəzərə alınıb.

T burada «hələ məlum olmayan tip» deməkdir. first(['Baku', 'Ganja']) çağırışında TypeScript arqumentə baxır və T-nin string olduğunu özü çıxarır. Tipi açıq da göstərmək olar: first<boolean>([]). Bu, boş massiv kimi TypeScript-in tipi özü tapa bilmədiyi hallarda lazım olur.

Generik interfeyslər

Tipin özü də parametr qəbul edə bilər. Server hər dəfə eyni quruluşda cavab verir — status və verilənlər — amma verilənlər hər sorğuda fərqlidir. Hər hal üçün ayrıca interfeys yazmaq əvəzinə bir generik interfeys yazırıq. Əslində sən artıq generiklərdən istifadə etmisən: Array<string> və Promise<number> də generik tiplərdir.

TypeScript
interface ApiResponse<T> {
  status: number;
  data: T;
}

type User = { id: number; name: string };

const userResponse: ApiResponse<User> = {
  status: 200,
  data: { id: 1, name: 'Leyla' },
};

const tagsResponse: ApiResponse<string[]> = {
  status: 200,
  data: ['typescript', 'generics'],
};

console.log(userResponse.data.name, tagsResponse.data.length);
Gözlənilən nəticə
Leyla 2

Məhdudiyyətlər: extends və keyof

Bəzən T «istənilən tip» ola bilməz. İki qiymətdən uzununu qaytaran funksiyaya length xassəsi lazımdır. T extends { length: number } yazılışı məhdudiyyətdir: T yalnız length xassəsi olan tip ola bilər — sətir, massiv və s. Ədədlərdə isə length yoxdur:

TypeScript
function longest<T extends { length: number }>(a: T, b: T): T {
  return a.length >= b.length ? a : b;
}

console.log(longest('Baku', 'Sumgait'));
console.log(longest([1, 2, 3], [4, 5]));
longest(10, 20);
Text
longest.ts:7:9 - error TS2345: Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.

7 longest(10, 20);
          ~~
Səhvli sətri silsən, proqram Sumgait və [ 1, 2, 3 ] çap edəcək.

keyof T operatoru obyekt tipinin bütün açarlarının birləşməsini verir: { title: string; year: number } üçün bu, 'title' | 'year'-dir. T[K] isə həmin açardakı qiymətin tipidir. Onları birləşdirəndə yalnız mövcud xassəni qəbul edən və düzgün tipi qaytaran funksiya alınır:

TypeScript
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const book = { title: 'Ali and Nino', year: 1937 };

const title = getProperty(book, 'title');
const year = getProperty(book, 'year');
console.log(title.toUpperCase(), year + 1);
getProperty(book, 'author');
Text
book.ts:10:19 - error TS2345: Argument of type '"author"' is not assignable to parameter of type '"title" | "year"'.

10 getProperty(book, 'author');
                     ~~~~~~~~
title string, year isə number tipini alır. Mövcud olmayan 'author' açarı rədd edilir.

Köməkçi tiplər

TypeScript-də generiklər üzərində qurulmuş hazır köməkçi tiplər var. Onlar mövcud tipdən yenisini düzəldir, beləliklə, eyni xassələri iki dəfə yazmalı olmursan. Ən çox işlənənləri bunlardır:

TipNə edir
Partial<T>bütün xassələri qeyri-məcburi edir
Required<T>bütün xassələri məcburi edir
Readonly<T>bütün xassələri yalnız oxunan edir
Pick<T, K>yalnız seçilmiş K xassələrini saxlayır
Omit<T, K>K xassələrindən başqa hamısını saxlayır
Record<K, V>açarları K, qiymətləri V tipli obyekt
ReturnType<F>F funksiyasının qaytardığı tip
TypeScript
interface Product {
  id: number;
  name: string;
  price: number;
  stock: number;
}

const laptop: Product = { id: 1, name: 'Laptop', price: 1500, stock: 4 };

function update(product: Product, changes: Partial<Product>): Product {
  return { ...product, ...changes };
}

type ProductCard = Pick<Product, 'name' | 'price'>;
type NewProduct = Omit<Product, 'id'>;

const card: ProductCard = { name: laptop.name, price: laptop.price };
const draft: NewProduct = { name: 'Mouse', price: 25, stock: 30 };

console.log(update(laptop, { price: 1350 }));
console.log(card, draft.name);
Gözlənilən nəticə
{ id: 1, name: 'Laptop', price: 1350, stock: 4 }
{ name: 'Laptop', price: 1500 } Mouse
Partial yeniləmə üçün (yalnız dəyişən xassələr), Omit<Product, 'id'> yeni məhsul üçün (id-ni verilənlər bazası verir), Pick isə kiçik kart üçün.
TypeScript
type City = 'Baku' | 'Ganja' | 'Shaki';

const deliveryDays: Record<City, number> = {
  Baku: 1,
  Ganja: 2,
  Shaki: 3,
};

function createUser(name: string, age: number) {
  return { name, age, createdAt: '2025-09-01' };
}

type User = ReturnType<typeof createUser>;

const user: User = createUser('Elvin', 16);
console.log(deliveryDays.Ganja, user.name, user.createdAt);
Gözlənilən nəticə
2 Elvin 2025-09-01
Record<City, number> hər şəhər üçün qiymət tələb edir: Shaki-ni unutsan, TS2741 xətası çıxacaq.

Əsas fikirlər

  • Generik tipi parametr kimi qəbul edir: function first<T>(items: T[]): T | undefined.
  • T adətən arqumentdən çıxarılır; lazım olanda açıq yazılır: first<boolean>([]).
  • T extends X tip parametrini məhdudlaşdırır; K extends keyof T yalnız mövcud açarlara icazə verir.
  • Partial, Pick, Omit, Record, ReturnType mövcud tiplərdən yenilərini düzəldir.
  • Tip parametri ən azı iki yeri əlaqələndirmirsə, generik lazım deyil.

Özünü yoxla

10 sual. Hər düzgün cavab XP qazandırır.

1 / 10
function first<T>(items: T[]): T | undefined yazılışında <T> nədir?