Eesti

Õppige selgeks TypeScripti utiliittüübid: võimsad tööriistad tüübimuutusteks, koodi taaskasutatavuse parandamiseks ja tüübiohutuse suurendamiseks teie rakendustes.

TypeScript'i utiliittüübid: sisseehitatud tüübimanipulatsiooni tööriistad

TypeScript on võimas keel, mis toob staatilise tüüpimise JavaScripti. Üks selle põhiomadusi on võime tüüpe manipuleerida, mis võimaldab arendajatel luua robustsemat ja hooldatavamat koodi. TypeScript pakub komplekti sisseehitatud utiliittüüpe, mis lihtsustavad tavalisi tüübimuutusi. Need utiliittüübid on hindamatud tööriistad tüübiohutuse suurendamiseks, koodi taaskasutatavuse parandamiseks ja arendusprotsessi sujuvamaks muutmiseks. See põhjalik juhend uurib kõige olulisemaid TypeScripti utiliittüüpe, pakkudes praktilisi näiteid ja rakendatavaid teadmisi, mis aitavad teil need selgeks õppida.

Mis on TypeScript'i utiliittüübid?

Utiliittüübid on eelmääratletud tüübioperaatorid, mis muudavad olemasolevad tüübid uuteks tüüpideks. Need on TypeScripti keelde sisse ehitatud ja pakuvad lühikest ning deklaratiivset viisi tavaliste tüübimanipulatsioonide teostamiseks. Utiliittüüpide kasutamine võib oluliselt vähendada korduvkoodi hulka ning muuta teie tüübimääratlused väljendusrikkamaks ja kergemini mõistetavaks.

Mõelge neist kui funktsioonidest, mis opereerivad tüüpidega väärtuste asemel. Nad võtavad sisendiks tüübi ja tagastavad väljundiks muudetud tüübi. See võimaldab teil luua keerukaid tüübisuhteid ja -muutusi minimaalse koodiga.

Miks kasutada utiliittüüpe?

On mitmeid kaalukaid põhjuseid, miks lisada utiliittüübid oma TypeScripti projektidesse:

Olulisemad TypeScript'i utiliittüübid

Uurime mõningaid kõige sagedamini kasutatavaid ja kasulikumaid utiliittüüpe TypeScriptis. Käsitleme nende eesmärki, süntaksit ja pakume praktilisi näiteid nende kasutuse illustreerimiseks.

1. Partial<T>

Utiliittüüp Partial<T> muudab kõik tüübi T omadused valikuliseks. See on kasulik, kui soovite luua uue tüübi, millel on mõned või kõik olemasoleva tüübi omadused, kuid te ei soovi, et kõik neist oleksid kohustuslikud.

Süntaks:

type Partial<T> = { [P in keyof T]?: T[P]; };

Näide:

interface User {
 id: number;
 name: string;
 email: string;
}

type OptionalUser = Partial<User>; // Kõik omadused on nüüd valikulised

const partialUser: OptionalUser = {
 name: "Alice", // Määratud on ainult nime omadus
};

Kasutusjuhtum: Objekti uuendamine ainult teatud omadustega. Kujutage näiteks ette kasutajaprofiili uuendamise vormi. Te ei soovi, et kasutajad peaksid korraga igat välja uuendama.

2. Required<T>

Utiliittüüp Required<T> muudab kõik tüübi T omadused kohustuslikuks. See on vastand tüübile Partial<T>. See on kasulik, kui teil on valikuliste omadustega tüüp ja soovite tagada, et kõik omadused oleksid olemas.

Süntaks:

type Required<T> = { [P in keyof T]-?: T[P]; };

Näide:

interface Config {
 apiKey?: string;
 apiUrl?: string;
}

type CompleteConfig = Required<Config>; // Kõik omadused on nüüd kohustuslikud

const config: CompleteConfig = {
 apiKey: "your-api-key",
 apiUrl: "https://example.com/api",
};

Kasutusjuhtum: Tagamine, et kõik konfiguratsiooniseaded on enne rakenduse käivitamist määratud. See aitab vältida puuduvate või defineerimata seadete põhjustatud käitusaja vigu.

3. Readonly<T>

Utiliittüüp Readonly<T> muudab kõik tüübi T omadused kirjutuskaitstuks. See takistab teil kogemata muuta objekti omadusi pärast selle loomist. See soodustab muutumatust ja parandab teie koodi prognoositavust.

Süntaks:

type Readonly<T> = { readonly [P in keyof T]: T[P]; };

Näide:

interface Product {
 id: number;
 name: string;
 price: number;
}

type ImmutableProduct = Readonly<Product>; // Kõik omadused on nüüd kirjutuskaitstud

const product: ImmutableProduct = {
 id: 123,
 name: "Example Product",
 price: 25.99,
};

// product.price = 29.99; // Viga: 'price' väärtust ei saa omistada, sest see on kirjutuskaitsega omadus.

Kasutusjuhtum: Muutumatute andmestruktuuride, näiteks konfiguratsiooniobjektide või andmeedastusobjektide (DTO-de) loomine, mida ei tohiks pärast loomist muuta. See on eriti kasulik funktsionaalse programmeerimise paradigmades.

4. Pick<T, K extends keyof T>

Utiliittüüp Pick<T, K extends keyof T> loob uue tüübi, valides tüübist T omaduste komplekti K. See on kasulik, kui vajate ainult osa olemasoleva tüübi omadustest.

Süntaks:

type Pick<T, K extends keyof T> = { [P in K]: T[P]; };

Näide:

interface Employee {
 id: number;
 name: string;
 department: string;
salary: number;
}

type EmployeeNameAndDepartment = Pick<Employee, "name" | "department">; // Valitakse ainult nimi ja osakond

const employeeInfo: EmployeeNameAndDepartment = {
 name: "Bob",
 department: "Engineering",
};

Kasutusjuhtum: Spetsialiseeritud andmeedastusobjektide (DTO-de) loomine, mis sisaldavad ainult konkreetse operatsiooni jaoks vajalikke andmeid. See võib parandada jõudlust ja vähendada võrgu kaudu edastatavate andmete hulka. Kujutage ette, et saadate kliendile kasutajaandmeid, kuid välistate tundliku teabe nagu palga. Saaksite kasutada Pick'i, et saata ainult `id` ja `name`.

5. Omit<T, K extends keyof any>

Utiliittüüp Omit<T, K extends keyof any> loob uue tüübi, jättes tüübist T välja omaduste komplekti K. See on vastand tüübile Pick<T, K extends keyof T> ja on kasulik, kui soovite olemasolevast tüübist teatud omadusi välistada.

Süntaks:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

Näide:

interface Event {
 id: number;
 title: string;
description: string;
 date: Date;
 location: string;
}

type EventSummary = Omit<Event, "description" | "location">; // Jäetakse välja kirjeldus ja asukoht

const eventPreview: EventSummary = {
 id: 1,
 title: "Conference",
 date: new Date(),
};

Kasutusjuhtum: Andmemudelite lihtsustatud versioonide loomine konkreetsetel eesmärkidel, näiteks sündmuse kokkuvõtte kuvamine ilma täieliku kirjelduse ja asukohata. Seda saab kasutada ka tundlike väljade eemaldamiseks enne andmete saatmist kliendile.

6. Exclude<T, U>

Utiliittüüp Exclude<T, U> loob uue tüübi, välistades tüübist T kõik tüübid, mis on omistatavad tüübile U. See on kasulik, kui soovite eemaldada teatud tüüpe ühendtüübist (union type).

Süntaks:

type Exclude<T, U> = T extends U ? never : T;

Näide:

type AllowedFileTypes = "image" | "video" | "audio" | "document";
type MediaFileTypes = "image" | "video" | "audio";

type DocumentFileTypes = Exclude<AllowedFileTypes, MediaFileTypes>; // "document"

const fileType: DocumentFileTypes = "document";

Kasutusjuhtum: Ühendtüübi filtreerimine, et eemaldada spetsiifilisi tüüpe, mis ei ole konkreetses kontekstis asjakohased. Näiteks võite soovida välistada teatud failitüübid lubatud failitüüpide loendist.

7. Extract<T, U>

Utiliittüüp Extract<T, U> loob uue tüübi, eraldades tüübist T kõik tüübid, mis on omistatavad tüübile U. See on vastand tüübile Exclude<T, U> ja on kasulik, kui soovite valida ühendtüübist spetsiifilisi tüüpe.

Süntaks:

type Extract<T, U> = T extends U ? T : never;

Näide:

type InputTypes = string | number | boolean | null | undefined;
type PrimitiveTypes = string | number | boolean;

type NonNullablePrimitives = Extract<InputTypes, PrimitiveTypes>; // string | number | boolean

const value: NonNullablePrimitives = "hello";

Kasutusjuhtum: Spetsiifiliste tüüpide valimine ühendtüübist teatud kriteeriumide alusel. Näiteks võite soovida eraldada kõik primitiivsed tüübid ühendtüübist, mis sisaldab nii primitiivseid kui ka objektitüüpe.

8. NonNullable<T>

Utiliittüüp NonNullable<T> loob uue tüübi, välistades tüübist T väärtused null ja undefined. See on kasulik, kui soovite tagada, et tüüp ei saa olla null ega undefined.

Süntaks:

type NonNullable<T> = T extends null | undefined ? never : T;

Näide:

type MaybeString = string | null | undefined;

type DefinitelyString = NonNullable<MaybeString>; // string

const message: DefinitelyString = "Hello, world!";

Kasutusjuhtum: Tagamine, et väärtus ei ole null ega undefined enne sellega operatsiooni teostamist. See aitab vältida ootamatutest null- või undefined-väärtustest põhjustatud käitusaja vigu. Mõelge stsenaariumile, kus peate töötlema kasutaja aadressi ja on oluline, et aadress ei oleks enne mis tahes toimingut null.

9. ReturnType<T extends (...args: any) => any>

Utiliittüüp ReturnType<T extends (...args: any) => any> eraldab funktsioonitüübi T tagastustüübi. See on kasulik, kui soovite teada, mis tüüpi väärtust funktsioon tagastab.

Süntaks:

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

Näide:

function fetchData(url: string): Promise<{ data: any }> {
 return fetch(url).then(response => response.json());
}

type FetchDataReturnType = ReturnType<typeof fetchData>; // Promise<{ data: any }>

async function processData(data: FetchDataReturnType) {
 // ...
}

Kasutusjuhtum: Funktsiooni tagastatava väärtuse tüübi määramine, eriti asünkroonsete operatsioonide või keerukate funktsioonisignatuuridega tegelemisel. See võimaldab teil tagada, et käsitlete tagastatud väärtust õigesti.

10. Parameters<T extends (...args: any) => any>

Utiliittüüp Parameters<T extends (...args: any) => any> eraldab funktsioonitüübi T parameetrite tüübid ennikuna (tuple). See on kasulik, kui soovite teada, mis tüüpi argumente funktsioon aktsepteerib.

Süntaks:

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

Näide:

function createUser(name: string, age: number, email: string): void {
 // ...
}

type CreateUserParams = Parameters<typeof createUser>; // [string, number, string]

function logUser(...args: CreateUserParams) {
 console.log("Creating user with:", args);
}

Kasutusjuhtum: Funktsiooni aktsepteeritavate argumentide tüüpide määramine, mis võib olla kasulik geneeriliste funktsioonide või dekoraatorite loomisel, mis peavad töötama erinevate signatuuridega funktsioonidega. See aitab tagada tüübiohutuse argumentide dünaamilisel edastamisel funktsioonile.

11. ConstructorParameters<T extends abstract new (...args: any) => any>

Utiliittüüp ConstructorParameters<T extends abstract new (...args: any) => any> eraldab konstruktorfunktsiooni tüübi T parameetrite tüübid ennikuna. See on kasulik, kui soovite teada, mis tüüpi argumente konstruktor aktsepteerib.

Süntaks:

type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;

Näide:

class Logger {
 constructor(public prefix: string, public enabled: boolean) {}
 log(message: string) {
 if (this.enabled) {
 console.log(`${this.prefix}: ${message}`);
 }
 }
}

type LoggerConstructorParams = ConstructorParameters<typeof Logger>; // [string, boolean]

function createLogger(...args: LoggerConstructorParams) {
 return new Logger(...args);
}

Kasutusjuhtum: Sarnane tüübile Parameters, kuid spetsiifiliselt konstruktorfunktsioonide jaoks. See aitab tehaste (factories) või sõltuvuste süstimise (dependency injection) süsteemide loomisel, kus peate dünaamiliselt instantseerima erinevate konstruktorisignatuuridega klasse.

12. InstanceType<T extends abstract new (...args: any) => any>

Utiliittüüp InstanceType<T extends abstract new (...args: any) => any> eraldab konstruktorfunktsiooni tüübi T instantsi tüübi. See on kasulik, kui soovite teada, mis tüüpi objekti konstruktor loob.

Süntaks:

type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;

Näide:

class Greeter {
 greeting: string;
 constructor(message: string) {
 this.greeting = message;
 }
 greet() {
 return "Hello, " + this.greeting;
 }
}

type GreeterInstance = InstanceType<typeof Greeter>; // Greeter

const myGreeter: GreeterInstance = new Greeter("World");
console.log(myGreeter.greet());

Kasutusjuhtum: Konstruktori loodud objekti tüübi määramine, mis on kasulik päriluse või polümorfismiga töötamisel. See pakub tüübiohutut viisi klassi instantsile viitamiseks.

13. Record<K extends keyof any, T>

Utiliittüüp Record<K extends keyof any, T> konstrueerib objektitüübi, mille omaduste võtmed on K ja mille omaduste väärtused on T. See on kasulik sõnastikulaadsete tüüpide loomiseks, kus teate võtmeid ette.

Süntaks:

type Record<K extends keyof any, T> = { [P in K]: T; };

Näide:

type CountryCode = "US" | "CA" | "GB" | "DE";

type CurrencyMap = Record<CountryCode, string>; // { US: string; CA: string; GB: string; DE: string; }

const currencies: CurrencyMap = {
 US: "USD",
 CA: "CAD",
 GB: "GBP",
 DE: "EUR",
};

Kasutusjuhtum: Sõnastikulaadsete objektide loomine, kus teil on kindel komplekt võtmeid ja soovite tagada, et kõikidel võtmetel oleks kindlat tüüpi väärtused. See on tavaline konfiguratsioonifailide, andmete vastendamise või otsingutabelitega töötamisel.

Kohandatud utiliittüübid

Kuigi TypeScripti sisseehitatud utiliittüübid on võimsad, saate luua ka oma kohandatud utiliittüüpe, et lahendada oma projektide spetsiifilisi vajadusi. See võimaldab teil kapseldada keerukaid tüübimuutusi ja neid oma koodibaasis taaskasutada.

Näide:

// Utiliittüüp, et saada objekti võtmed, millel on kindel tüüp
type KeysOfType<T, U> = { [K in keyof T]: T[K] extends U ? K : never }[keyof T];

interface Person {
 name: string;
 age: number;
 address: string;
 phoneNumber: number;
}

type StringKeys = KeysOfType<Person, string>; // "name" | "address"

Parimad praktikad utiliittüüpide kasutamiseks

Kokkuvõte

TypeScripti utiliittüübid on võimsad tööriistad, mis võivad oluliselt parandada teie koodi tüübiohutust, taaskasutatavust ja hooldatavust. Nende utiliittüüpide valdamisega saate kirjutada robustsemaid ja väljendusrikkamaid TypeScripti rakendusi. See juhend on käsitlenud kõige olulisemaid TypeScripti utiliittüüpe, pakkudes praktilisi näiteid ja rakendatavaid teadmisi, mis aitavad teil neid oma projektidesse integreerida.

Ärge unustage katsetada nende utiliittüüpidega ja uurida, kuidas neid saab kasutada konkreetsete probleemide lahendamiseks oma koodis. Mida tuttavamaks te nendega saate, seda sagedamini leiate end neid kasutamas puhtamate, hooldatavamate ja tüübiohutumate TypeScripti rakenduste loomiseks. Olenemata sellest, kas te ehitate veebirakendusi, serveripoolseid rakendusi või midagi vahepealset, pakuvad utiliittüübid väärtuslikku tööriistakomplekti teie arendusprotsessi ja koodi kvaliteedi parandamiseks. Nende sisseehitatud tüübimanipulatsiooni tööriistade võimendamisega saate avada TypeScripti täieliku potentsiaali ja kirjutada koodi, mis on nii väljendusrikas kui ka robustne.