Lietuvių

Išlaisvinkite TypeScript pagalbinių tipų galią, kad rašytumėte švaresnį, lengviau prižiūrimą ir saugesnį kodą. Naršykite praktinius pritaikymus su realaus pasaulio pavyzdžiais kūrėjams visame pasaulyje.

TypeScript pagalbinių tipų įvaldymas: praktinis vadovas pasauliniams kūrėjams

TypeScript siūlo galingą įtaisytų pagalbinių tipų rinkinį, kuris gali žymiai padidinti jūsų kodo tipo saugumą, skaitomumą ir prižiūrimumą. Šie pagalbiniai tipai iš esmės yra iš anksto apibrėžtos tipo transformacijos, kurias galite pritaikyti esamiems tipams, taip išvengdami pasikartojančio ir klaidų linkusio kodo rašymo. Šiame vadove bus nagrinėjami įvairūs pagalbiniai tipai su praktiniais pavyzdžiais, kurie atitinka kūrėjų visame pasaulyje poreikius.

Kodėl naudoti pagalbinius tipus?

Pagalbiniai tipai sprendžia dažnus tipo manipuliavimo scenarijus. Pasinaudodami jais, galite:

Pagrindiniai pagalbiniai tipai

Partial

Partial sukuria tipą, kuriame visos T savybės yra nustatytos kaip pasirenkamos. Tai ypač naudinga, kai norite sukurti tipą daliniams atnaujinimams arba konfigūracijos objektams.

Pavyzdys:

Įsivaizduokite, kad kuriate elektroninės prekybos platformą su klientais iš įvairių regionų. Jūs turite Customer tipą:


interface Customer {
  id: string;
  firstName: string;
  lastName: string;
  email: string;
  phoneNumber: string;
  address: {
    street: string;
    city: string;
    country: string;
    postalCode: string;
  };
  preferences?: {
    language: string;
    currency: string;
  }
}

Atnaujindami kliento informaciją, galbūt nenorėsite reikalauti visų laukų. Partial leidžia apibrėžti tipą, kuriame visos Customer savybės yra pasirenkamos:


type PartialCustomer = Partial<Customer>;

function updateCustomer(id: string, updates: PartialCustomer): void {
  // ... įgyvendinimas kliento atnaujinimui su nurodytu ID
}

updateCustomer("123", { firstName: "John", lastName: "Doe" }); // Galioja
updateCustomer("456", { address: { city: "London" } }); // Galioja

Readonly

Readonly sukuria tipą, kuriame visos T savybės yra nustatytos kaip readonly, užkertant kelią modifikavimui po inicializavimo. Tai yra vertinga užtikrinant nekeičiamumą.

Pavyzdys:

Apsvarstykite konfigūracijos objektą savo pasaulinei programai:


interface AppConfig {
  apiUrl: string;
  theme: string;
  supportedLanguages: string[];
  version: string; // Pridėta versija
}

const config: AppConfig = {
  apiUrl: "https://api.example.com",
  theme: "dark",
  supportedLanguages: ["en", "fr", "de", "es", "zh"],
  version: "1.0.0"
};

Norėdami išvengti atsitiktinio konfigūracijos modifikavimo po inicializavimo, galite naudoti Readonly:


type ReadonlyAppConfig = Readonly<AppConfig>;

const readonlyConfig: ReadonlyAppConfig = {
  apiUrl: "https://api.example.com",
  theme: "dark",
  supportedLanguages: ["en", "fr", "de", "es", "zh"],
  version: "1.0.0"
};

// readonlyConfig.apiUrl = "https://newapi.example.com"; // Klaida: Negalima priskirti 'apiUrl', nes tai yra tik skaitymui skirta savybė.

Pick

Pick sukuria tipą, parinkdamas savybių rinkinį KT, kur K yra eilutinių literalų tipų sąjunga, atstovaujanti savybių pavadinimus, kuriuos norite įtraukti.

Pavyzdys:

Tarkime, kad turite Event sąsają su įvairiomis savybėmis:


interface Event {
  id: string;
  title: string;
  description: string;
  location: string;
  startTime: Date;
  endTime: Date;
  organizer: string;
  attendees: string[];
}

Jei jums reikia tik title, location ir startTime konkrečiam rodymo komponentui, galite naudoti Pick:


type EventSummary = Pick<Event, "title" | "location" | "startTime">;

function displayEventSummary(event: EventSummary): void {
  console.log(`Įvykis: ${event.title} at ${event.location} on ${event.startTime}`);
}

Omit

Omit sukuria tipą, išskirdamas savybių rinkinį KT, kur K yra eilutinių literalų tipų sąjunga, atstovaujanti savybių pavadinimus, kuriuos norite išskirti. Tai yra Pick priešingybė.

Pavyzdys:

Naudojant tą pačią Event sąsają, jei norite sukurti tipą naujiems įvykiams kurti, galbūt norėsite išskirti id savybę, kuri paprastai generuojama backend'e:


type NewEvent = Omit<Event, "id">;

function createEvent(event: NewEvent): void {
  // ... įgyvendinimas naujo įvykio kūrimui
}

Record

Record sukuria objekto tipą, kurio savybių raktai yra K, o savybių reikšmės yra T. K gali būti eilutinių literalų tipų, skaičių literalų tipų arba simbolių sąjunga. Tai puikiai tinka žodynų ar žemėlapių kūrimui.

Pavyzdys:

Įsivaizduokite, kad jums reikia saugoti savo programos vartotojo sąsajos vertimus. Galite naudoti Record, kad apibrėžtumėte savo vertimų tipą:


type Translations = Record<string, string>;

const enTranslations: Translations = {
  "hello": "Hello",
  "goodbye": "Goodbye",
  "welcome": "Welcome to our platform!"
};

const frTranslations: Translations = {
  "hello": "Bonjour",
  "goodbye": "Au revoir",
  "welcome": "Bienvenue sur notre plateforme !"
};

function translate(key: string, language: string): string {
  const translations = language === "en" ? enTranslations : frTranslations; //Supaprastinta
  return translations[key] || key; // Atsarginis variantas į raktą, jei vertimas nerastas
}

console.log(translate("hello", "en")); // Išvestis: Hello
console.log(translate("hello", "fr")); // Išvestis: Bonjour
console.log(translate("nonexistent", "en")); // Išvestis: nonexistent

Exclude

Exclude sukuria tipą, išskirdamas iš T visus sąjungos narius, kurie gali būti priskirti U. Tai naudinga filtruojant konkrečius tipus iš sąjungos.

Pavyzdys:

Galite turėti tipą, atstovaujantį skirtingus įvykių tipus:


type EventType = "concert" | "conference" | "workshop" | "webinar";

Jei norite sukurti tipą, kuris išskiria „webinar“ įvykius, galite naudoti Exclude:


type PhysicalEvent = Exclude<EventType, "webinar">;

// PhysicalEvent dabar yra "concert" | "conference" | "workshop"

function attendPhysicalEvent(event: PhysicalEvent): void {
  console.log(`Dalyvauju ${event}`);
}

// attendPhysicalEvent("webinar"); // Klaida: argumento tipas '"webinar"' negali būti priskirtas parametrui, kurio tipas yra '"concert" | "conference" | "workshop"'.

attendPhysicalEvent("concert"); // Galioja

Extract

Extract sukuria tipą, ištraukdamas iš T visus sąjungos narius, kurie gali būti priskirti U. Tai yra Exclude priešingybė.

Pavyzdys:

Naudojant tą patį EventType, galite ištraukti webinar įvykio tipą:


type OnlineEvent = Extract<EventType, "webinar">;

// OnlineEvent dabar yra "webinar"

function attendOnlineEvent(event: OnlineEvent): void {
  console.log(`Dalyvauju ${event} internetu`);
}

attendOnlineEvent("webinar"); // Galioja
// attendOnlineEvent("concert"); // Klaida: argumento tipas '"concert"' negali būti priskirtas parametrui, kurio tipas yra '"webinar"'.

NonNullable

NonNullable sukuria tipą, išskirdamas null ir undefinedT.

Pavyzdys:


type MaybeString = string | null | undefined;

type DefinitelyString = NonNullable<MaybeString>;

// DefinitelyString dabar yra string

function processString(str: DefinitelyString): void {
  console.log(str.toUpperCase());
}

// processString(null); // Klaida: argumento tipas 'null' negali būti priskirtas parametrui, kurio tipas yra 'string'.
// processString(undefined); // Klaida: argumento tipas 'undefined' negali būti priskirtas parametrui, kurio tipas yra 'string'.
processString("hello"); // Galioja

ReturnType

ReturnType sukuria tipą, kurį sudaro funkcijos T grąžinamas tipas.

Pavyzdys:


function greet(name: string): string {
  return `Hello, ${name}!`;
}

type Greeting = ReturnType<typeof greet>;

// Greeting dabar yra string

const message: Greeting = greet("World");

console.log(message);

Parameters

Parameters sukuria rinkinio tipą iš funkcijos tipo T parametrų tipų.

Pavyzdys:


function logEvent(eventName: string, eventData: object): void {
  console.log(`Įvykis: ${eventName}`, eventData);
}

type LogEventParams = Parameters<typeof logEvent>;

// LogEventParams dabar yra [eventName: string, eventData: object]

const params: LogEventParams = ["user_login", { userId: "123", timestamp: Date.now() }];

logEvent(...params);

ConstructorParameters

ConstructorParameters sukuria rinkinio arba masyvo tipą iš konstruktoriaus funkcijos tipo T parametrų tipų. Jis nustato argumentų, kuriuos reikia perduoti klasės konstruktoriui, tipus.

Pavyzdys:


class Greeter {
  greeting: string;

  constructor(message: string) {
    this.greeting = message;
  }

  greet() {
    return "Hello, " + this.greeting;
  }
}


type GreeterParams = ConstructorParameters<typeof Greeter>;

// GreeterParams dabar yra [message: string]

const paramsGreeter: GreeterParams = ["World"];
const greeterInstance = new Greeter(...paramsGreeter);

console.log(greeterInstance.greet()); // Išvestis: Hello, World

Required

Required sukuria tipą, kurį sudaro visos T savybės, nustatytos kaip privalomos. Tai padaro visas pasirenkamas savybes privalomomis.

Pavyzdys:


interface UserProfile {
  name: string;
  age?: number;
  email?: string;
}

type RequiredUserProfile = Required<UserProfile>;

// RequiredUserProfile dabar yra { name: string; age: number; email: string; }

const completeProfile: RequiredUserProfile = {
  name: "Alice",
  age: 30,
  email: "alice@example.com"
};

// const incompleteProfile: RequiredUserProfile = { name: "Bob" }; // Klaida: Savybė 'age' trūksta tipe '{ name: string; }', bet yra privaloma tipe 'Required'.

Išplėstiniai pagalbiniai tipai

Šablonų literalų tipai

Šablonų literalų tipai leidžia kurti naujus eilutinių literalų tipus, sujungiant esamus eilutinių literalų tipus, skaičių literalų tipus ir dar daugiau. Tai leidžia galingą eilutėmis pagrįstą tipo manipuliavimą.

Pavyzdys:


type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type APIEndpoint = `/api/users` | `/api/products`;

type RequestURL = `${HTTPMethod} ${APIEndpoint}`;

// RequestURL dabar yra "GET /api/users" | "POST /api/users" | "PUT /api/users" | "DELETE /api/users" | "GET /api/products" | "POST /api/products" | "PUT /api/products" | "DELETE /api/products"

function makeRequest(url: RequestURL): void {
  console.log(`Vykdomas užklausimas į ${url}`);
}

makeRequest("GET /api/users"); // Galioja
// makeRequest("INVALID /api/users"); // Klaida

Sąlyginiai tipai

Sąlyginiai tipai leidžia apibrėžti tipus, kurie priklauso nuo sąlygos, išreikštos kaip tipo ryšys. Jie naudoja infer raktinį žodį, kad ištrauktų tipo informaciją.

Pavyzdys:


type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

// Jei T yra Promise, tada tipas yra U; kitu atveju tipas yra T.

async function fetchData(): Promise<number> {
  return 42;
}


type Data = UnwrapPromise<ReturnType<typeof fetchData>>;

// Data dabar yra number

function processData(data: Data): void {
  console.log(data * 2);
}

processData(await fetchData());

Praktinis pritaikymas ir realaus pasaulio scenarijai

Panagrinėkime sudėtingesnius realaus pasaulio scenarijus, kuriuose pagalbiniai tipai spindi.

1. Formų apdorojimas

Dirbdami su formomis, dažnai turite scenarijų, kai reikia atspindėti pradinės formos reikšmes, atnaujintas formos reikšmes ir galutines pateiktas reikšmes. Pagalbiniai tipai gali padėti efektyviai valdyti šias skirtingas būsenas.


interface FormData {
  firstName: string;
  lastName: string;
  email: string;
  country: string; // Privaloma
  city?: string; // Pasirenkama
  postalCode?: string;
  newsletterSubscription?: boolean;
}

// Pradinės formos reikšmės (pasirenkami laukai)
type InitialFormValues = Partial<FormData>;

// Atnaujintos formos reikšmės (kai kurių laukų gali trūkti)
type UpdatedFormValues = Partial<FormData>;

// Privalomi laukai pateikimui
type RequiredForSubmission = Required<Pick<FormData, 'firstName' | 'lastName' | 'email' | 'country'>>;

// Naudokite šiuos tipus savo formos komponentuose
function initializeForm(initialValues: InitialFormValues): void { }
function updateForm(updates: UpdatedFormValues): void {}
function submitForm(data: RequiredForSubmission): void {}


const initialForm: InitialFormValues = { newsletterSubscription: true };

const updateFormValues: UpdatedFormValues = {
    firstName: "John",
    lastName: "Doe"
};

// const submissionData: RequiredForSubmission = { firstName: "test", lastName: "test", email: "test" }; // KLAIDA: Trūksta 'country' 
const submissionData: RequiredForSubmission = { firstName: "test", lastName: "test", email: "test", country: "USA" }; //GERAI


2. API duomenų transformavimas

Naudodami duomenis iš API, galbūt norėsite transformuoti duomenis į kitokį formatą savo programai. Pagalbiniai tipai gali padėti apibrėžti transformuotų duomenų struktūrą.


interface APIResponse {
  user_id: string;
  first_name: string;
  last_name: string;
  email_address: string;
  profile_picture_url: string;
  is_active: boolean;
}

// Transformuokite API atsakymą į labiau įskaitomą formatą
type UserData = {
  id: string;
  fullName: string;
  email: string;
  avatar: string;
  active: boolean;
};

function transformApiResponse(response: APIResponse): UserData {
  return {
    id: response.user_id,
    fullName: `${response.first_name} ${response.last_name}`,
    email: response.email_address,
    avatar: response.profile_picture_url,
    active: response.is_active
  };
}

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


// Jūs netgi galite primesti tipą:

function saferTransformApiResponse(response: APIResponse): UserData {
    const {user_id, first_name, last_name, email_address, profile_picture_url, is_active} = response;
    const transformed: UserData = {
        id: user_id,
        fullName: `${first_name} ${last_name}`,
        email: email_address,
        avatar: profile_picture_url,
        active: is_active
    };

    return transformed;
}

3. Konfigūracijos objektų apdorojimas

Konfigūracijos objektai yra dažni daugelyje programų. Pagalbiniai tipai gali padėti apibrėžti konfigūracijos objekto struktūrą ir užtikrinti, kad jis būtų naudojamas teisingai.


interface AppSettings {
  theme: "light" | "dark";
  language: string;
  notificationsEnabled: boolean;
  apiUrl?: string; // Pasirenkamas API URL skirtingoms aplinkoms
  timeout?: number;  //Pasirenkama
}

// Numatytieji nustatymai
const defaultSettings: AppSettings = {
  theme: "light",
  language: "en",
  notificationsEnabled: true
};

// Funkcija sujungti vartotojo nustatymus su numatytaisiais nustatymais
function mergeSettings(userSettings: Partial<AppSettings>): AppSettings {
  return { ...defaultSettings, ...userSettings };
}

// Naudokite sujungtus nustatymus savo programoje
const mergedSettings = mergeSettings({ theme: "dark", apiUrl: "https://customapi.example.com" });
console.log(mergedSettings);

Patarimai, kaip efektyviai naudoti pagalbinius tipus

  • Pradėkite nuo paprasto: Pradėkite nuo pagrindinių pagalbinių tipų, tokių kaip Partial ir Readonly, prieš pereidami prie sudėtingesnių.
  • Naudokite aprašomuosius pavadinimus: Suteikite savo tipo pseudonimams prasmingus pavadinimus, kad pagerintumėte skaitomumą.
  • Sujunkite pagalbinius tipus: Galite sujungti kelis pagalbinius tipus, kad pasiektumėte sudėtingas tipo transformacijas.
  • Pasinaudokite redaktoriaus palaikymu: Pasinaudokite puikiu TypeScript redaktoriaus palaikymu, kad ištirtumėte pagalbinių tipų poveikį.
  • Supraskite pagrindines sąvokas: Tvirtas TypeScript tipo sistemos supratimas yra būtinas efektyviam pagalbinių tipų naudojimui.

Išvada

TypeScript pagalbiniai tipai yra galingi įrankiai, kurie gali žymiai pagerinti jūsų kodo kokybę ir prižiūrimumą. Suprasdami ir efektyviai taikydami šiuos pagalbinius tipus, galite rašyti švaresnes, saugesnes ir patikimesnes programas, kurios atitinka pasaulinės kūrimo aplinkos poreikius. Šiame vadove pateikiama išsami bendrų pagalbinių tipų apžvalga ir praktiniai pavyzdžiai. Eksperimentuokite su jais ir ištirkite jų potencialą pagerinti savo TypeScript projektus. Atminkite, kad naudodami pagalbinius tipus, pirmenybę teikite skaitomumui ir aiškumui, ir visada stenkitės rašyti kodą, kurį būtų lengva suprasti ir prižiūrėti, nepaisant to, kur yra jūsų kolegos kūrėjai.