AtklÄjiet uzlabotus TypeScript Ä£enÄriskos tipus! Ceļvedis pÄta keyof operatoru un indeksa piekļuves tipus, to atŔķirÄ«bas un kombinÄÅ”anu robustÄm, tipu droÅ”Äm lietotnÄm.
Uzlaboti Ä£enÄriskie ierobežojumi: Keyof Operator vs. Indeksa piekļuves tipi paskaidroti
PlaÅ”ajÄ un nepÄrtraukti mainÄ«gajÄ programmatÅ«ras izstrÄdes ainavÄ TypeScript ir kļuvis par kritiski svarÄ«gu rÄ«ku stabilu, mÄrogojamu un uzturamu lietojumprogrammu veidoÅ”anai. TÄ statiskÄs tipizÄÅ”anas spÄjas dod iespÄju izstrÄdÄtÄjiem visÄ pasaulÄ savlaicÄ«gi atklÄt kļūdas, uzlabot koda lasÄmÄ«bu un veicinÄt sadarbÄ«bu dažÄdÄs komandÄs un projektos. TypeScript jaudas pamatÄ ir tÄ sarežģītÄ tipu sistÄma, jo Ä«paÅ”i tÄs Ä£enÄriskie tipi un uzlabotÄs tipu manipulÄcijas funkcijas. KamÄr daudzi izstrÄdÄtÄji ir apmierinÄti ar pamata Ä£enÄriskajiem tipiem, patiesa TypeScript apguve prasa dziļÄku izpratni par sarežģītÄkiem jÄdzieniem, piemÄram, Ä£enÄriskajiem ierobežojumiem, the keyof operatoru un indeksa piekļuves tipiem.
Å is visaptveroÅ”ais ceļvedis ir paredzÄts izstrÄdÄtÄjiem, kuri vÄlas uzlabot savas TypeScript prasmes, pÄrsniedzot pamatus, lai izmantotu pilnu valodas izteiksmÄ«go jaudu. MÄs dosimies detalizÄtÄ ceļojumÄ, analizÄjot keyof operatora un indeksa piekļuves tipu nianses, pÄtot to individuÄlÄs stiprÄs puses, saprotot, kad katru no tiem izmantot, un, galvenais, atklÄjot, kÄ tos apvienot, lai izveidotu neticami elastÄ«gu un tipu droÅ”u kodu. NeatkarÄ«gi no tÄ, vai veidojat globÄlu uzÅÄmuma lietojumprogrammu, atvÄrtÄ koda bibliotÄku vai sniedzat ieguldÄ«jumu starpkultÅ«ru attÄ«stÄ«bas projektÄ, Ŕīs uzlabotÄs metodes ir neaizvietojamas augstas kvalitÄtes TypeScript rakstīŔanai.
AtklÄsim patiesi uzlabotu Ä£enÄrisko ierobežojumu noslÄpumus un stiprinÄsim jÅ«su TypeScript izstrÄdi!
StÅ«rakmens: TypeScript Ä£enÄrisko tipu izpratne
Pirms mÄs iedziļinÄmies keyof un indeksa piekļuves tipu specifiskajÄs niansÄs, ir bÅ«tiski stingri aptvert Ä£enÄrisko tipu koncepciju un to, kÄpÄc tie ir tik svarÄ«gi mÅ«sdienu programmatÅ«ras izstrÄdÄ. Ä¢enÄriskie tipi ļauj rakstÄ«t komponentus, kas var strÄdÄt ar dažÄdiem datu tipiem, nevis bÅ«t ierobežotiem ar vienu. Tas nodroÅ”ina milzÄ«gu elastÄ«bu un atkÄrtotu izmantojamÄ«bu, kas ir vissvarÄ«gÄkais mÅ«sdienu straujajÄ izstrÄdes vidÄ, Ä«paÅ”i, ja tiek apkalpotas dažÄdas datu struktÅ«ras un biznesa loÄ£ika globÄlÄ mÄrogÄ.
Pamata Ä£enÄriskie tipi: ElastÄ«gs pamats
IedomÄjieties, ka jums ir nepiecieÅ”ama funkcija, kas atgriež masÄ«va pirmo elementu. Bez Ä£enÄriskajiem tipiem jÅ«s to varÄtu uzrakstÄ«t Å”Ädi:
function getFirstElement(arr: any[]): any {
if (arr.length === 0) {
return undefined;
}
return arr[0];
}
// Usage with numbers
const numbers = [1, 2, 3];
const firstNumber = getFirstElement(numbers); // type: any
// Usage with strings
const names = ['Alice', 'Bob'];
const firstName = getFirstElement(names); // type: any
// Problem: We lose type information!
const lengthOfFirstName = (firstName as string).length; // Requires type assertion
ProblÄma ir tÄda, ka any pilnÄ«bÄ izdzÄÅ” tipu droŔību. Ä¢enÄriskie tipi to atrisina, ļaujot tvert argumenta tipu un izmantot to kÄ atgrieÅ”anas tipu:
function getFirstElement<T>(arr: T[]): T {
if (arr.length === 0) {
// Depending on strict settings, you might need to return T | undefined
// For simplicity, let's assume non-empty arrays or handle undefined explicitly.
// A more robust signature might be T[] => T | undefined.
return undefined as any; // Or handle more carefully
}
return arr[0];
}
const numbers = [1, 2, 3];
const firstNumber = getFirstElement(numbers); // type: number
const names = ['Alice', 'Bob'];
const firstName = getFirstElement(names); // type: string
// Type safety maintained!
const lengthOfFirstName = firstName.length; // No type assertion needed, TypeScript knows it's a string
Å eit <T> deklarÄ tipa mainÄ«go T. Kad izsaucat getFirstElement ar skaitļu masÄ«vu, T kļūst par number. Kad izsaucat to ar virknÄm, T kļūst par string. Tas ir Ä£enÄrisko tipu fundamentÄlais spÄks: tipu inferencÄÅ”ana un atkÄrtota izmantojamÄ«ba, nezaudÄjot droŔību.
Ä¢enÄriskie ierobežojumi ar extends
Lai gan Ä£enÄriskie tipi piedÄvÄ milzÄ«gu elastÄ«bu, reizÄm ir nepiecieÅ”ams ierobežot tipus, ko var izmantot ar Ä£enÄrisku komponentu. PiemÄram, ko darÄ«t, ja jÅ«su funkcija paredz, ka Ä£enÄriskajam tipam T vienmÄr ir jÄbÅ«t noteiktai Ä«paŔībai vai metodei? Å eit talkÄ nÄk Ä£enÄriskie ierobežojumi, izmantojot atslÄgvÄrdu extends.
ApskatÄ«sim funkciju, kas reÄ£istrÄ elementa ID. Ne visiem tipiem ir id Ä«paŔība. Mums ir jÄierobežo T, lai nodroÅ”inÄtu, ka tam vienmÄr ir id Ä«paŔība ar tipu number (vai string, atkarÄ«bÄ no prasÄ«bÄm).
interface HasId {
id: number;
}
function logId<T extends HasId>(item: T): void {
console.log(`ID: ${item.id}`);
}
// Works correctly
logId({ id: 1, name: 'Product A' }); // ID: 1
logId({ id: 2, quantity: 10 }); // ID: 2
// Error: Argument of type '{ name: string; }' is not assignable to parameter of type 'HasId'.
// Property 'id' is missing in type '{ name: string; }' but required in type 'HasId'.
// logId({ name: 'Product B' });
Izmantojot <T extends HasId>, mÄs sakÄm TypeScript, ka T ir jÄbÅ«t pieŔķiramam HasId tipam. Tas nozÄ«mÄ, ka jebkuram objektam, kas tiek nodots logId, ir jÄbÅ«t id: number Ä«paŔībai, tÄdÄjÄdi nodroÅ”inot tipu droŔību un novÄrÅ”ot izpildes laika kļūdas. Å Ä« pamatizpratne par Ä£enÄriskajiem tipiem un ierobežojumiem ir izŔķiroÅ”a, kad iedziļinÄmies sarežģītÄkÄs tipu manipulÄcijÄs.
Dziļa iedziļinÄÅ”anÄs: keyof operators
keyof operators ir spÄcÄ«gs rÄ«ks TypeScript valodÄ, kas ļauj no konkrÄta tipa iegÅ«t visus publiskos Ä«paŔību nosaukumus (atslÄgas) un pÄrvÄrst tos par virkÅu literÄļu apvienoto tipu. IedomÄjieties to kÄ saraksta Ä£enerÄÅ”anu ar visiem derÄ«gajiem Ä«paÅ”umu piekļuves veidiem objektam. Tas ir neticami noderÄ«gi, lai izveidotu ļoti elastÄ«gas, taÄu tipu droÅ”as funkcijas, kas darbojas ar objektu Ä«paŔībÄm, kas ir bieža prasÄ«ba datu apstrÄdÄ, konfigurÄcijÄ un UI izstrÄdÄ dažÄdÄs globÄlÄs lietojumprogrammÄs.
Ko dara keyof
VienkÄrÅ”i sakot, objekta tipam T, keyof T veido virknes literÄļu tipu apvienÄ«bu, kas attÄlo T Ä«paŔību nosaukumus. Tas ir kÄ jautÄt: "KÄdas ir visas iespÄjamÄs atslÄgas, ko varu izmantot, lai piekļūtu Ŕī tipa objekta Ä«paŔībÄm?"
Sintakse un pamata lietoŔana
Sintakse ir vienkÄrÅ”a: keyof TypeName.
interface User {
id: number;
name: string;
email?: string;
age: number;
}
type UserKeys = keyof User; // Type is 'id' | 'name' | 'email' | 'age'
const userKey: UserKeys = 'name'; // Valid
// const invalidKey: UserKeys = 'address'; // Error: Type '"address"' is not assignable to type 'UserKeys'.
class Product {
public productId: string;
private _cost: number;
protected _warehouseId: string;
constructor(id: string, cost: number) {
this.productId = id;
this._cost = cost;
this._warehouseId = 'default';
}
public getCost(): number {
return this._cost;
}
}
type ProductKeys = keyof Product; // Type is 'productId' | 'getCost'
// Note: private and protected members are not included in keyof for classes,
// as they are not publicly accessible keys.
KÄ redzams, keyof pareizi identificÄ visus publiski pieejamos Ä«paŔību nosaukumus, ieskaitot metodes (kas ir Ä«paŔības, kurÄs atrodas funkciju vÄrtÄ«bas), bet izslÄdz privÄtos un aizsargÄtos dalÄ«bniekus. Å Äda uzvedÄ«ba atbilst tÄ mÄrÄ·im: identificÄt derÄ«gas atslÄgas Ä«paŔību piekļuvei.
keyof Ä£enÄriskajos ierobežojumos
Patiesais keyof spÄks atklÄjas, kad tas tiek apvienots ar Ä£enÄriskajiem ierobežojumiem. Å Ä« kombinÄcija ļauj rakstÄ«t funkcijas, kas var strÄdÄt ar jebkuru objektu, bet tikai ar tÄm Ä«paŔībÄm, kas patieÅ”Äm pastÄv Å”ajÄ objektÄ, tÄdÄjÄdi nodroÅ”inot tipu droŔību kompilÄÅ”anas laikÄ.
ApskatÄ«sim bieži sastopamu scenÄriju: utilitÄrÄ funkcija, lai droÅ”i iegÅ«tu Ä«paŔības vÄrtÄ«bu no objekta.
1. piemÄrs: Funkcijas getProperty izveide
Bez keyof jÅ«s varÄtu Ä·erties pie any vai mazÄk droÅ”as pieejas:
function getPropertyUnsafe(obj: any, key: string): any {
return obj[key];
}
const myUser = { id: 1, name: 'Charlie' };
const userName = getPropertyUnsafe(myUser, 'name'); // Returns 'Charlie', but type is any
const userAddress = getPropertyUnsafe(myUser, 'address'); // Returns undefined, no compile-time error
Tagad ieviesīsim keyof, lai padarītu Ŕo funkciju stabilu un tipu droŔu:
/**
* Safely retrieves a property from an object.
* @template T The type of the object.
* @template K The type of the key, constrained to be a key of T.
* @param obj The object to query.
* @param key The key (property name) to retrieve.
* @returns The value of the property at the given key.
*/
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
interface Employee {
employeeId: number;
firstName: string;
lastName: string;
department: string;
}
const employee: Employee = {
employeeId: 101,
firstName: 'Anna',
lastName: 'Johnson',
department: 'Engineering'
};
// Valid usage:
const empFirstName = getProperty(employee, 'firstName'); // type: string, value: 'Anna'
console.log(`Employee First Name: ${empFirstName}`);
const empId = getProperty(employee, 'employeeId'); // type: number, value: 101
console.log(`Employee ID: ${empId}`);
// Invalid usage (compile-time error):
// Argument of type '"salary"' is not assignable to parameter of type '"employeeId" | "firstName" | "lastName" | "department"'.
// const empSalary = getProperty(employee, 'salary');
interface Configuration {
locale: 'en-US' | 'es-ES' | 'fr-FR';
theme: 'light' | 'dark';
maxItemsPerPage: number;
}
const appConfig: Configuration = {
locale: 'en-US',
theme: 'dark',
maxItemsPerPage: 20
};
const currentTheme = getProperty(appConfig, 'theme'); // type: 'light' | 'dark', value: 'dark'
console.log(`Current Theme: ${currentTheme}`);
Sadalīsim function getProperty<T, K extends keyof T>(obj: T, key: K): T[K]:
<T>: DeklarÄ Ä£enÄrisku tipa parametruTobjektam.<K extends keyof T>: DeklarÄ Ä£enÄrisku tipa parametruKatslÄgai. Å Ä« ir svarÄ«gÄkÄ daļa. Tas ierobežoKbÅ«t vienam no virknes literÄļa tipiem, kas attÄloTatslÄgu. TÄtad, jaTirEmployee, tadKir jÄbÅ«t'employeeId' | 'firstName' | 'lastName' | 'department'.(obj: T, key: K): Funkcijas parametri.objirTtips, unkeyirKtips.: T[K]: Å is ir indeksa piekļuves tips (ko mÄs detalizÄti aplÅ«kosim nÄkamajÄ nodaļÄ), kas Å”eit tiek izmantots atgrieÅ”anas tipa norÄdīŔanai. Tas nozÄ«mÄ "Ä«paŔības tips ar atslÄguKobjekta tipÄT". JaTirEmployeeunKir'firstName', tadT[K]atrisinÄs uzstring. JaKir'employeeId', tas atrisinÄs uznumber.
keyof ierobežojumu priekŔrocības
- KompilÄÅ”anas laika droŔība: NovÄrÅ” piekļuvi neeksistÄjoÅ”Äm Ä«paŔībÄm, samazinot izpildes laika kļūdas.
- Uzlabota izstrÄdÄtÄja pieredze: NodroÅ”ina inteliÄ£entus automÄtiskÄs pabeigÅ”anas ieteikumus atslÄgÄm, izsaucot funkciju.
- Uzlabota lasÄmÄ«ba: Tipa paraksts skaidri norÄda, ka atslÄgai ir jÄpieder objektam.
- Stabila refaktorizÄcija: Ja pÄrdÄvÄjat Ä«paŔību
Employee, TypeScript nekavÄjoties atzÄ«mÄsgetPropertyizsaukumus, kas izmanto veco atslÄgu.
Uzlaboti keyof scenÄriji
AtslÄgu iterÄÅ”ana
Lai gan keyof pats par sevi ir tipa operators, tas bieži vien sniedz informÄciju par to, kÄ varÄtu veidot funkcijas, kas iterÄ pa objekta atslÄgÄm, nodroÅ”inot, ka izmantotÄs atslÄgas vienmÄr ir derÄ«gas.
function logAllProperties<T extends object>(obj: T): void {
// Here, Object.keys returns string[], not keyof T, so we often need assertions
// or to be careful. However, keyof T guides our thinking for type safety.
(Object.keys(obj) as Array<keyof T>).forEach(key => {
// We know 'key' is a valid key for 'obj'
console.log(`${String(key)}: ${obj[key]}`);
});
}
interface MenuItem {
id: string;
label: string;
price: number;
available: boolean;
}
const coffee: MenuItem = {
id: 'cappuccino',
label: 'Cappuccino',
price: 4.50,
available: true
};
logAllProperties(coffee);
// Output:
// id: cappuccino
// label: Cappuccino
// price: 4.5
// available: true
Å ajÄ piemÄrÄ keyof T darbojas kÄ konceptuÄls vadoÅ”ais princips tam, ko Object.keys *vajadzÄtu* atgriezt ideÄlÄ tipu droÅ”Ä pasaulÄ. Mums bieži ir nepiecieÅ”ams tipa apgalvojums as Array<keyof T>, jo Object.keys izpildes laikÄ ir mazÄk tipu apzinÄts nekÄ TypeScript kompilÄÅ”anas laika tipu sistÄma. Tas izceļ mijiedarbÄ«bu starp izpildes laika JavaScript un kompilÄÅ”anas laika TypeScript.
keyof ar apvienotajiem tipiem
Kad lietojat keyof apvienotajam tipam, tas atgriež atslÄgu ŔķÄlumu no visiem apvienÄ«bas tipiem. Tas nozÄ«mÄ, ka tas ietver tikai tÄs atslÄgas, kas ir kopÄ«gas visiem apvienÄ«bas locekļiem.
interface Apple {
color: string;
sweetness: number;
}
interface Orange {
color: string;
citrus: boolean;
}
type Fruit = Apple | Orange;
type FruitKeys = keyof Fruit; // Type is 'color'
// 'sweetness' is only in Apple, 'citrus' is only in Orange.
// 'color' is common to both.
Å Ä« uzvedÄ«ba ir svarÄ«gi atcerÄties, jo tÄ nodroÅ”ina, ka jebkura atslÄga, kas izvÄlÄta no FruitKeys, vienmÄr bÅ«s derÄ«ga Ä«paŔība jebkuram Fruit tipa objektam (neatkarÄ«gi no tÄ, vai tas ir Apple vai Orange). Tas novÄrÅ” izpildes laika kļūdas, strÄdÄjot ar polimorfÄm datu struktÅ«rÄm.
keyof ar typeof
JÅ«s varat izmantot keyof kopÄ ar typeof, lai iegÅ«tu atslÄgas no objekta tipa tieÅ”i no tÄ vÄrtÄ«bas, kas ir Ä«paÅ”i noderÄ«gi konfigurÄcijas objektiem vai konstantÄm.
const APP_SETTINGS = {
API_URL: 'https://api.example.com',
TIMEOUT_MS: 5000,
DEBUG_MODE: false
};
type AppSettingKeys = keyof typeof APP_SETTINGS; // Type is 'API_URL' | 'TIMEOUT_MS' | 'DEBUG_MODE'
function getAppSetting<K extends AppSettingKeys>(key: K): (typeof APP_SETTINGS)[K] {
return APP_SETTINGS[key];
}
const apiUrl = getAppSetting('API_URL'); // type: string
const debugMode = getAppSetting('DEBUG_MODE'); // type: boolean
// const invalidSetting = getAppSetting('LOG_LEVEL'); // Error
Å is modelis ir ļoti efektÄ«vs, lai saglabÄtu tipu droŔību, mijiedarbojoties ar globÄlajiem konfigurÄcijas objektiem, nodroÅ”inot konsekvenci dažÄdos moduļos un komandÄs, kas ir Ä«paÅ”i vÄrtÄ«gi liela mÄroga projektos ar daudzveidÄ«giem ieguldÄ«tÄjiem.
Indeksa piekļuves tipu (Lookup Types) atklÄÅ”ana
KamÄr keyof dod jums Ä«paŔību nosaukumus, indeksa piekļuves tips (ko bieži dÄvÄ arÄ« par meklÄÅ”anas tipu) ļauj izvilkt konkrÄtas Ä«paŔības tipu no cita tipa. Tas ir kÄ jautÄt: "KÄds ir vÄrtÄ«bas tips pie Ŕīs konkrÄtÄs atslÄgas Å”ajÄ objekta tipÄ?" Å Ä« spÄja ir fundamentÄla, lai veidotu tipus, kas ir atvasinÄti no esoÅ”ajiem tipiem, uzlabojot atkÄrtotu izmantojamÄ«bu un samazinot liekumu jÅ«su tipu definÄ«cijÄs.
Ko dara indeksa piekļuves tipi
Indeksa piekļuves tips izmanto kvadrÄtiekavu notÄciju (tÄpat kÄ Ä«paŔību piekļuvei JavaScript valodÄ) tipu lÄ«menÄ«, lai meklÄtu tipu, kas saistÄ«ts ar Ä«paŔības atslÄgu. Tas ir bÅ«tisks, lai dinamiski veidotu tipus, pamatojoties uz citu tipu struktÅ«ru.
Sintakse un pamata lietoŔana
Sintakse ir TypeName[KeyType], kur KeyType parasti ir virknes literÄļa tips vai virknes literÄļa tipu apvienÄ«ba, kas atbilst derÄ«gÄm TypeName atslÄgÄm.
interface ProductInfo {
name: string;
price: number;
category: 'Electronics' | 'Apparel' | 'Books';
details: { weight: string; dimensions: string };
}
type ProductNameType = ProductInfo['name']; // Type is string
type ProductPriceType = ProductInfo['price']; // Type is number
type ProductCategoryType = ProductInfo['category']; // Type is 'Electronics' | 'Apparel' | 'Books'
type ProductDetailsType = ProductInfo['details']; // Type is { weight: string; dimensions: string; }
// You can also use a union of keys:
type NameAndPrice = ProductInfo['name' | 'price']; // Type is string | number
// If a key doesn't exist, it's a compile-time error:
// type InvalidType = ProductInfo['nonExistentKey']; // Error: Property 'nonExistentKey' does not exist on type 'ProductInfo'.
Tas parÄda, kÄ indeksa piekļuves tipi ļauj precÄ«zi izvilkt konkrÄtas Ä«paŔības tipu vai vairÄku Ä«paŔību tipu apvienÄ«bu no esoÅ”as saskarnes vai tipa aizstÄjvÄrda. Tas ir ļoti vÄrtÄ«gi, lai nodroÅ”inÄtu tipu konsekvenci dažÄdÄs lielas lietojumprogrammas daļÄs, Ä«paÅ”i, ja lietojumprogrammas daļas varÄtu izstrÄdÄt dažÄdas komandas vai dažÄdÄs Ä£eogrÄfiskÄs vietÄs.
Indeksa piekļuves tipi Ä£enÄriskajos kontekstos
TÄpat kÄ keyof, indeksa piekļuves tipi iegÅ«st ievÄrojamu spÄku, ja tos izmanto Ä£enÄriskÄs definÄ«cijÄs. Tie ļauj dinamiski noteikt Ä£enÄriskÄs funkcijas vai utilitÄrÄ tipa atgrieÅ”anas tipu vai parametru tipu, pamatojoties uz ievades Ä£enÄrisko tipu un atslÄgu.
2. piemÄrs: AtkÄrtoti aplÅ«kota funkcija getProperty ar indeksa piekļuvi atgrieÅ”anas tipÄ
MÄs to jau redzÄjÄm darbÄ«bÄ ar mÅ«su getProperty funkciju, taÄu atkÄrtosim un uzsvÄrsim T[K] lomu:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
interface Customer {
id: string;
firstName: string;
lastName: string;
preferences: { email: boolean; sms: boolean };
}
const customer: Customer = {
id: 'cust-123',
firstName: 'Maria',
lastName: 'Gonzales',
preferences: { email: true, sms: false }
};
const customerFirstName = getProperty(customer, 'firstName'); // Type: string, Value: 'Maria'
const customerPreferences = getProperty(customer, 'preferences'); // Type: { email: boolean; sms: boolean; }, Value: { email: true, sms: false }
// You can even access nested properties, but the getProperty function itself
// only works for top-level keys. For nested access, you'd need a more complex generic.
// For example, to get customer.preferences.email, you'd chain calls or use a different utility.
// const customerEmailPref = getProperty(customer.preferences, 'email'); // Type: boolean, Value: true
Å eit T[K] ir vissvarÄ«gÄkais. Tas pasaka TypeScript, ka getProperty atgrieÅ”anas tipam ir precÄ«zi jÄbÅ«t Ä«paŔības K tipam objektÄ T. Tas padara funkciju tik tipu droÅ”u un daudzpusÄ«gu, pielÄgojot tÄs atgrieÅ”anas tipu, pamatojoties uz norÄdÄ«to atslÄgu.
KonkrÄtas Ä«paŔības tipa izvilkÅ”ana
Indeksa piekļuves tipi nav paredzÄti tikai funkciju atgrieÅ”anas tipiem. Tie ir neticami noderÄ«gi jaunu tipu definÄÅ”anai, pamatojoties uz esoÅ”o tipu daļÄm. Tas ir bieži sastopams scenÄrijos, kad jÄizveido jauns objekts, kas satur tikai noteiktas Ä«paŔības, vai kad jÄdefinÄ tips UI komponentam, kas parÄda tikai datu apakÅ”kopu no lielÄka datu modeļa.
interface FinancialReport {
reportId: string;
dateGenerated: Date;
totalRevenue: number;
expenses: number;
profit: number;
currency: 'USD' | 'EUR' | 'JPY';
}
type EssentialReportInfo = {
reportId: FinancialReport['reportId'];
date: FinancialReport['dateGenerated'];
currency: FinancialReport['currency'];
};
const summary: EssentialReportInfo = {
reportId: 'FR-2023-Q4',
date: new Date(),
currency: 'EUR' // This is type-checked correctly
};
// We can also create a type for a property's value using a type alias:
type CurrencyType = FinancialReport['currency']; // Type is 'USD' | 'EUR' | 'JPY'
function formatAmount(amount: number, currency: CurrencyType): string {
return `${amount.toFixed(2)} ${currency}`;
}
console.log(formatAmount(1234.56, 'USD')); // 1234.56 USD
// console.log(formatAmount(789.00, 'GBP')); // Error: Type '"GBP"' is not assignable to type 'CurrencyType'.
Tas parÄda, kÄ indeksa piekļuves tipus var izmantot jaunu tipu konstruÄÅ”anai vai parametru paredzamÄ tipa definÄÅ”anai, nodroÅ”inot, ka dažÄdas jÅ«su sistÄmas daļas ievÄro konsekventas definÄ«cijas, kas ir izŔķiroÅ”i lielÄm, izkliedÄtÄm izstrÄdes komandÄm.
Uzlaboti indeksa piekļuves tipu scenÄriji
Indeksa piekļuve ar apvienotajiem tipiem
Kad indeksa piekļuves tipÄ kÄ atslÄgu izmantojat literÄlo tipu apvienÄ«bu, TypeScript atgriež Ä«paŔību tipu apvienÄ«bu, kas atbilst katrai atslÄgai apvienÄ«bÄ.
interface EventData {
type: 'click' | 'submit' | 'scroll';
timestamp: number;
userId: string;
target?: HTMLElement;
value?: string;
}
type EventIdentifiers = EventData['type' | 'userId']; // Type is 'click' | 'submit' | 'scroll' | string
// Because 'type' is a union of string literals, and 'userId' is a string,
// the resulting type is 'click' | 'submit' | 'scroll' | string, which simplifies to string.
// Let's refine for a more illustrative example:
interface Book {
title: string;
author: string;
pages: number;
isAvailable: boolean;
}
type BookStringOrNumberProps = Book['title' | 'author' | 'pages']; // Type is string | number
// 'title' is string, 'author' is string, 'pages' is number.
// The union of these is string | number.
Tas ir spÄcÄ«gs veids, kÄ veidot tipus, kas attÄlo "jebkuru no Ŕīm konkrÄtajÄm Ä«paŔībÄm", kas ir noderÄ«gi, strÄdÄjot ar elastÄ«gÄm datu saskarnÄm vai ievieÅ”ot Ä£enÄriskos datu sasaistes mehÄnismus.
Nosacītie tipi un indeksa piekļuve
Indeksa piekļuves tipi bieži tiek apvienoti ar nosacÄ«tajiem tipiem, lai radÄ«tu ļoti dinamiskas un adaptÄ«vas tipu transformÄcijas. NosacÄ«tie tipi ļauj atlasÄ«t tipu, pamatojoties uz nosacÄ«jumu.
interface Device {
id: string;
name: string;
firmwareVersion: string;
lastPing: Date;
isOnline: boolean;
}
// Type that extracts only string properties from a given object type T
type StringProperties<T> = {
[K in keyof T]: T[K] extends string ? K : never;
}[keyof T];
type DeviceStringKeys = StringProperties<Device>; // Type is 'id' | 'name' | 'firmwareVersion'
// This creates a new type that contains only the string properties of Device
type DeviceStringsOnly = Pick<Device, DeviceStringKeys>;
/*
Equivalent to:
interface DeviceStringsOnly {
id: string;
name: string;
firmwareVersion: string;
}
*/
const myDeviceStrings: DeviceStringsOnly = {
id: 'dev-001',
name: 'Sensor Unit Alpha',
firmwareVersion: '1.2.3'
};
// myDeviceStrings.isOnline; // Error: Property 'isOnline' does not exist on type 'DeviceStringsOnly'.
Å is uzlabotais modelis parÄda, kÄ keyof (iekÅ” K in keyof T) un indeksa piekļuves tipi (T[K]) cieÅ”i sadarbojas ar nosacÄ«tajiem tipiem (extends string ? K : never), lai veiktu sarežģītu tipu filtrÄÅ”anu un transformÄciju. Å Äda veida uzlabota tipu manipulÄcija ir nenovÄrtÄjama, veidojot ļoti adaptÄ«vus un izteiksmÄ«gus API un utilitÄtes bibliotÄkas.
keyof operators pret indeksa piekļuves tipiem: TieÅ”s salÄ«dzinÄjums
Å ajÄ brÄ«dÄ« jums varÄtu rasties jautÄjumi par keyof un indeksa piekļuves tipu atŔķirÄ«gajÄm lomÄm un to, kad katru no tiem izmantot. Lai gan tie bieži parÄdÄs kopÄ, to fundamentÄlie mÄrÄ·i ir atŔķirÄ«gi, taÄu papildina viens otru.
Ko tie atgriež
keyof T: Atgriež virknes literÄļa tipu apvienÄ«bu, kas attÄloTÄ«paŔību nosaukumus. Tas dod jums Ä«paŔību "etiÄ·etes" vai "identifikatorus".T[K](Indeksa piekļuves tips): Atgriež vÄrtÄ«bas tipu, kas saistÄ«ts ar atslÄguKtipÄT. Tas dod jums "satura tipu" pie konkrÄtas etiÄ·etes.
Kad katru izmantot
- Izmantojiet
keyof, ja jums nepiecieÅ”ams:- Ierobežot Ä£enÄrisku tipa parametru, lai tas bÅ«tu derÄ«gs cita tipa Ä«paŔības nosaukums (piemÄram,
K extends keyof T). - UzskaitÄ«t visus iespÄjamos Ä«paŔību nosaukumus konkrÄtam tipam.
- Izveidot utilitÄros tipus, kas iterÄ pa atslÄgÄm, piemÄram,
Pick,Omitvai pielÄgotos kartÄÅ”anas tipus.
- Ierobežot Ä£enÄrisku tipa parametru, lai tas bÅ«tu derÄ«gs cita tipa Ä«paŔības nosaukums (piemÄram,
- Izmantojiet indeksa piekļuves tipus (
T[K]), ja jums nepiecieÅ”ams:- IegÅ«t konkrÄtas Ä«paŔības tipu no objekta tipa.
- Dinamiski noteikt funkcijas atgrieÅ”anas tipu, pamatojoties uz objektu un atslÄgu (piemÄram,
getPropertyatgrieÅ”anas tips). - Izveidot jaunus tipus, kas sastÄv no specifiskiem Ä«paŔību tipiem no citiem tipiem.
- Veikt tipa lÄ«meÅa meklÄÅ”anu.
AtŔķirÄ«ba ir smalka, bet izŔķiroÅ”a: keyof ir par *atslÄgÄm*, savukÄrt indeksa piekļuves tipi ir par *vÄrtÄ«bu tipiem* pie Ŕīm atslÄgÄm.
SinerÄ£iskais spÄks: keyof un indeksa piekļuves tipu izmantoÅ”ana kopÄ
Å o jÄdzienu jaudÄ«gÄkÄs pielietoÅ”anas iespÄjas bieži ietver to apvienoÅ”anu. Kanoniskais piemÄrs ir mÅ«su getProperty funkcija:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
AnalizÄsim Å”o parakstu vÄlreiz, novÄrtÄjot sinerÄ£iju:
<T>: MÄs ievieÅ”am Ä£enÄrisko tipuTobjektam. Tas ļauj funkcijai darboties ar *jebkuru* objekta tipu.<K extends keyof T>: MÄs ievieÅ”am otru Ä£enÄrisko tipuKÄ«paŔības atslÄgai. AtslÄgvÄrdsextends keyof Tir vitÄli svarÄ«gs; tas nodroÅ”ina, ka funkcijai nodotaiskeyarguments ir jÄbÅ«t derÄ«gamobjÄ«paŔības nosaukumam. Ja Å”eit navkeyof,KvarÄtu bÅ«t jebkura virkne, padarot funkciju nedroÅ”u.(obj: T, key: K): Funkcijas parametri ir tipiTunK.: T[K]: Å is ir indeksa piekļuves tips. Tas dinamiski nosaka atgrieÅ”anas tipu. TÄ kÄKir ierobežots kÄTatslÄga,T[K]precÄ«zi dod mums vÄrtÄ«bas tipu pie konkrÄtÄs Ä«paŔības. Tas nodroÅ”ina spÄcÄ«gu tipu inferenci atgrieÅ”anas vÄrtÄ«bai. BezT[K]atgrieÅ”anas tips bÅ«tuanyvai plaÅ”Äks tips, zaudÄjot specifiskumu.
SarežģītÄku utilitÄtes tipu veidoÅ”ana
Daudzi no TypeScript iebÅ«vÄtajiem utilitÄtes tipiem, piemÄram, Pick<T, K> un Omit<T, K>, iekÅ”Äji izmanto keyof un indeksa piekļuves tipus. ApskatÄ«sim, kÄ varÄtu ieviest vienkÄrÅ”otu Pick versiju:
/**
* Constructs a type by picking the set of properties K from Type T.
* @template T The original type.
* @template K The union of keys to pick, which must be keys of T.
*/
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
interface ServerLog {
id: string;
timestamp: Date;
level: 'info' | 'warn' | 'error';
message: string;
sourceIp: string;
userId?: string;
}
type CriticalLogInfo = MyPick<ServerLog, 'id' | 'timestamp' | 'level' | 'message'>;
/*
Equivalent to:
interface CriticalLogInfo {
id: string;
timestamp: Date;
level: 'info' | 'warn' | 'error';
message: string;
}
*/
const errorLog: CriticalLogInfo = {
id: 'log-001',
timestamp: new Date(),
level: 'error',
message: 'Database connection failed'
};
// errorLog.sourceIp; // Error: Property 'sourceIp' does not exist on type 'CriticalLogInfo'.
MyPick<T, K extends keyof T> gadÄ«jumÄ:
K extends keyof T: NodroÅ”ina, ka atslÄgas, kuras vÄlamies izvÄlÄties (K), patieÅ”Äm ir derÄ«gas sÄkotnÄjÄ tipaTatslÄgas.[P in K]: Å is ir kartÄtais tips. Tas iterÄ pa katru literÄlo tipuPapvienotajÄ tipÄK.T[P]: Katrai atslÄgaiPtas izmanto indeksa piekļuves tipu, lai iegÅ«tu atbilstoÅ”Äs Ä«paŔības tipu no sÄkotnÄjÄ tipaT.
Å is piemÄrs lieliski ilustrÄ apvienoto spÄku, ļaujot jums izveidot jaunas, tipu droÅ”as struktÅ«ras, precÄ«zi atlasot un izvilkot daļas no esoÅ”ajiem tipiem. Å Ädi utilitÄrie tipi ir nenovÄrtÄjami datu konsekvences uzturÄÅ”anai sarežģītÄs sistÄmÄs, Ä«paÅ”i, ja dažÄdi komponenti (piemÄram, priekÅ”gala UI, aizmugursistÄmas pakalpojums, mobilÄ lietotne) var mijiedarboties ar dažÄdÄm koplietojama datu modeļa apakÅ”kopÄm.
Dinamiska Record tipu veidoŔana
UtilitÄtes tips Record<K, T> ir vÄl viens jaudÄ«gs iebÅ«vÄts tips, kas izveido objekta tipu, kura Ä«paŔību atslÄgas ir K tips un Ä«paŔību vÄrtÄ«bas ir T tips. JÅ«s varat apvienot keyof ar Record, lai dinamiski Ä£enerÄtu tipus vÄrdnÄ«cÄm vai kartÄm, kur atslÄgas ir atvasinÄtas no esoÅ”a tipa.
interface Permissions {
read: boolean;
write: boolean;
execute: boolean;
admin: boolean;
}
// Create a type that maps each permission key to a 'PermissionStatus'
type PermissionStatus = 'granted' | 'denied' | 'pending';
type PermissionsMapping = Record<keyof Permissions, PermissionStatus>;
/*
Equivalent to:
{
read: 'granted' | 'denied' | 'pending';
write: 'granted' | 'denied' | 'pending';
execute: 'granted' | 'denied' | 'pending';
admin: 'granted' | 'denied' | 'pending';
}
*/
const userPermissions: PermissionsMapping = {
read: 'granted',
write: 'denied',
execute: 'pending',
admin: 'denied'
};
// userPermissions.delete = 'granted'; // Error: Property 'delete' does not exist on type 'PermissionsMapping'.
Å is modelis ir ļoti noderÄ«gs, lai Ä£enerÄtu meklÄÅ”anas tabulas, statusa paneļus vai piekļuves kontroles sarakstus, kur atslÄgas ir tieÅ”i saistÄ«tas ar esoÅ”ajÄm datu modeļa Ä«paŔībÄm vai funkcionÄlajÄm iespÄjÄm.
Tipu kartÄÅ”ana ar keyof un indeksa piekļuvi
KartÄÅ”anas tipi ļauj transformÄt katru esoÅ”Ä tipa Ä«paŔību jaunÄ tipÄ. Å eit keyof un indeksa piekļuves tipi patiesi izceļas, ļaujot veikt sarežģītas tipu atvasinÄÅ”anas. Bieži sastopams lietojums ir visu objekta Ä«paŔību transformÄÅ”ana asinhronÄs operÄcijÄs, kas atspoguļo biežu modeli API dizainÄ vai notikumu vadÄ«tÄs arhitektÅ«rÄs.
PiemÄrs: MapToPromises<T>
Izveidosim utilitÄtes tipu, kas Åem objekta tipu T un transformÄ to jaunÄ tipÄ, kurÄ katras Ä«paŔības vÄrtÄ«ba ir iesaiÅota Promise.
/**
* Transforms an object type T into a new type where each property's value
* is wrapped in a Promise.
* @template T The original object type.
*/
type MapToPromises<T> = {
[P in keyof T]: Promise<T[P]>;
};
interface UserData {
id: string;
username: string;
email: string;
age: number;
}
type AsyncUserData = MapToPromises<UserData>;
/*
Equivalent to:
interface AsyncUserData {
id: Promise<string>;
username: Promise<string>;
email: Promise<string>;
age: Promise<number>;
}
*/
// Example usage:
async function fetchUserData(): Promise<AsyncUserData> {
return {
id: Promise.resolve('user-abc'),
username: Promise.resolve('global_dev'),
email: Promise.resolve('global.dev@example.com'),
age: Promise.resolve(30)
};
}
async function displayUser() {
const data = await fetchUserData();
const username = await data.username;
console.log(`Fetched Username: ${username}`); // Fetched Username: global_dev
const email = await data.email;
// console.log(email.toUpperCase()); // This would be type-safe (string methods available)
}
displayUser();
MapToPromises<T> gadÄ«jumÄ:
[P in keyof T]: Tas kartÄ visus Ä«paŔību atslÄgasPno ievades tipaT.keyof TnodroÅ”ina visu Ä«paŔību nosaukumu apvienÄ«bu.Promise<T[P]>: Katrai atslÄgaiPtas Åem sÄkotnÄjÄs Ä«paŔības tipuT[P](izmantojot indeksa piekļuves tipu) un iesaiÅo toPromise.
Tas ir spÄcÄ«gs demonstrÄjums tam, kÄ keyof un indeksa piekļuves tipi sadarbojas, lai definÄtu sarežģītas tipu transformÄcijas, ļaujot jums veidot ļoti izteiksmÄ«gus un tipu droÅ”us API asinhronÄm operÄcijÄm, datu keÅ”atmiÅai vai jebkuram scenÄrijam, kurÄ jums ir jÄmaina Ä«paŔību tipi konsekventÄ veidÄ. Å Ädas tipu transformÄcijas ir kritiskas izkliedÄtajÄs sistÄmÄs un mikropakalpojumu arhitektÅ«rÄs, kur datu formÄm var bÅ«t nepiecieÅ”ams pielÄgoties dažÄdÄs pakalpojumu robežÄs.
SecinÄjums: Tipu droŔības un elastÄ«bas apguve
MÅ«su padziļinÄtÄ iedziļinÄÅ”anÄs keyof un indeksa piekļuves tipos atklÄj tos ne tikai kÄ atseviŔķas funkcijas, bet kÄ papildinoÅ”us pÄ«lÄrus TypeScript uzlabotajÄ Ä£enÄrisko tipu sistÄmÄ. Tie dod iespÄju izstrÄdÄtÄjiem visÄ pasaulÄ veidot neticami elastÄ«gu, atkÄrtoti izmantojamu un, pats galvenais, tipu droÅ”u kodu. Sarežģītu lietojumprogrammu, dažÄdu komandu un globÄlas sadarbÄ«bas laikmetÄ koda kvalitÄtes un paredzamÄ«bas nodroÅ”inÄÅ”ana kompilÄÅ”anas laikÄ ir vissvarÄ«gÄkÄ. Å ie uzlabotie Ä£enÄriskie ierobežojumi ir bÅ«tiski rÄ«ki Å”ajÄ centienÄ.
Izprotot un efektÄ«vi izmantojot keyof, jÅ«s iegÅ«stat spÄju precÄ«zi atsaukties uz Ä«paŔību nosaukumiem un tos ierobežot, nodroÅ”inot, ka jÅ«su Ä£enÄriskÄs funkcijas un tipi darbojas tikai ar objekta derÄ«gajÄm daļÄm. Vienlaikus, apgÅ«stot indeksa piekļuves tipus (T[K]), jÅ«s atbloÄ·Äjat spÄju precÄ«zi izvilkt un atvasinÄt Å”o Ä«paŔību tipus, padarot jÅ«su tipu definÄ«cijas adaptÄ«vas un ļoti specifiskas.
SinerÄ£ija starp keyof un indeksa piekļuves tipiem, kÄ tas redzams tÄdos modeļos kÄ getProperty funkcija un pielÄgotie utilitÄtes tipi, piemÄram, MyPick vai MapToPromises, ir nozÄ«mÄ«gs solis tipu lÄ«meÅa programmÄÅ”anÄ. Å Ä«s tehnikas pÄrsniedz vienkÄrÅ”u datu aprakstīŔanu, ļaujot aktÄ«vi manipulÄt un transformÄt paÅ”us tipus, kas noved pie robustÄkas programmatÅ«ras arhitektÅ«ras un ievÄrojami uzlabotas izstrÄdÄtÄja pieredzes.
Praktiski padomi globÄlajiem izstrÄdÄtÄjiem:
- PieÅemiet Ä£enÄriskos tipus: SÄciet izmantot Ä£enÄriskos tipus pat vienkÄrÅ”ÄkÄm funkcijÄm. Jo agrÄk tos ieviesÄ«sit, jo dabiskÄki tie kļūs.
- DomÄjiet ierobežojumos: Ikreiz, kad rakstÄt Ä£enÄrisku funkciju, jautÄjiet sev: "KÄdÄm Ä«paŔībÄm vai metodÄm
Tir jÄbÅ«t, lai Ŕī funkcija darbotos?" Tas dabiski novedÄ«s pieextendsklauzulÄm unkeyof. - Izmantojiet indeksa piekļuvi: Ja jÅ«su Ä£enÄriskÄs funkcijas atgrieÅ”anas tips (vai parametra tips) ir atkarÄ«gs no citas Ä£enÄriskÄ tipa konkrÄtas Ä«paŔības, domÄjiet par
T[K]. - IzpÄtiet utilitÄtes tipus: IepazÄ«stieties ar TypeScript iebÅ«vÄtajiem utilitÄtes tipiem (
Pick,Omit,Record,Partial,Required) un novÄrojiet, kÄ tie izmanto Å”os jÄdzienus. MÄÄ£iniet atjaunot vienkÄrÅ”otas versijas, lai nostiprinÄtu izpratni. - DokumentÄjiet savus tipus: Sarežģītiem Ä£enÄriskiem tipiem, Ä«paÅ”i koplietojamÄs bibliotÄkÄs, sniedziet skaidrus komentÄrus, kas izskaidro to mÄrÄ·i un to, kÄ Ä£enÄriskie parametri tiek ierobežoti un izmantoti. Tas ievÄrojami veicina starptautisko komandu sadarbÄ«bu.
- PraktizÄjieties ar reÄliem scenÄrijiem: Pielietojiet Å”os jÄdzienus saviem ikdienas kodÄÅ”anas izaicinÄjumiem ā vai tas bÅ«tu elastÄ«gas datu tabulas veidoÅ”ana, tipu droÅ”a konfigurÄcijas ielÄdÄtÄja izveide vai atkÄrtoti izmantojama API klienta projektÄÅ”ana.
Uzlabotu Ä£enÄrisko ierobežojumu apguve ar keyof un indeksa piekļuves tipiem nav tikai par vairÄk TypeScript rakstīŔanu; tas ir par labÄka, droÅ”Äka un vieglÄk uzturama koda rakstīŔanu, kas var pÄrliecinoÅ”i darbinÄt lietojumprogrammas visÄs jomÄs un Ä£eogrÄfiskajÄs vietÄs. Turpiniet eksperimentÄt, turpiniet mÄcÄ«ties un dodiet spÄku saviem globÄlÄs izstrÄdes centieniem ar pilnu TypeScript tipu sistÄmas spÄku!