Bedste praksis i TypeScript-programmering

Bedste praksis i TypeScript-programmering

Denne artikel forklarer bedste praksis i TypeScript-programmering.

Denne guide forklarer praktiske bedste praksisser for at udnytte TypeScript’s typer for at reducere fejl og skrive mere læsbar kode.

YouTube Video

Bedste praksis i TypeScript-programmering

Den største fordel ved TypeScript er 'at forhindre fejl med typer og gøre intentionen med koden tydelig'.

Bedste praksis er ikke blot regler, men en samling af principper for at skrive sikker, læsbar og vedligeholdelsesvenlig kode. Nedenfor introducerer vi almindeligt anvendte bedste praksisser i TypeScript med praktiske eksempler.

Undgå any og giv altid typer meningsfulde definitioner

Lad os først se på punktet om at 'undgå any og give meningsfulde typer.'.

any deaktiverer fuldstændig typekontrol, hvilket modarbejder formålet med at bruge TypeScript. I stedet for blot at bruge any for at få tingene til at virke, er det vigtigt at give typer, der er så beskrivende som muligt.

1// Bad
2function parse(data: any) {
3  return data.value;
4}

Denne kode kan acceptere enhver værdi, så kørselsfejl kan ikke forhindres.

1// Good
2type ParsedData = {
3  value: string;
4};
5
6function parse(data: ParsedData): string {
7  return data.value;
8}

Ved at definere typer tydeliggør du formålet med input og output og øger sikkerheden.

Definer altid objektstrukturer eksplicit ved hjælp af type eller interface.

Lad os derefter se på punktet om 'altid eksplicit at definere objektstrukturer ved hjælp af type eller interface.'.

Hvis du bruger objekter ad hoc, kan deres struktur blive uklar. Udtræk altid typer for genbrugelighed og vedligeholdelse.

1// Bad
2function createUser(user: { name: string; age: number }) {
3  console.log(user.name);
4}

Selv i små kodeeksempler er det vigtigt at udvikle vanen med at adskille typer.

1// Good
2type User = {
3  name: string;
4  age: number;
5};
6
7function createUser(user: User): void {
8  console.log(user.name);
9}

Ved at navngive typer bliver det meget nemmere at forstå den samlede kodebase.

Brug unionstyper til præcist at repræsentere alle mulige tilstande.

Hvis du bruger rå string- eller number-typer til betingelser, kan uventede værdier slippe igennem. Ved at bruge unionstyper kan du kun repræsentere de tilladte tilstande på typeniveau.

1// Bad
2function setStatus(status: string) {
3  console.log(status);
4}

I denne kode kan meningsløse strenge eller forkerte værdier ikke opdages ved kompileringstidspunktet.

1// Good
2type Status = "idle" | "loading" | "success" | "error";
3
4function setStatus(status: Status): void {
5  console.log(status);
6}

Ved at bruge unionstyper kan du pålideligt eliminere 'umulige tilstande' under kompileringen. Som følge heraf vil sikkerheden i betingede grene og kodens pålidelighed blive forbedret.

Håndtér null og undefined eksplicit.

Lad os derefter se på punktet om 'eksplicit håndtering af null og undefined.'.

I TypeScript er det vigtigt at udtrykke en mulig fravær af en værdi i typen. Hvis du holder tingene uklare, kan de føre til kørselsfejl.

1type User = {
2  name: string;
3  email?: string;
4};

email findes måske ikke, så du bør håndtere det ud fra denne antagelse.

1function printEmail(user: User): void {
2  if (user.email) {
3    console.log(user.email);
4  }
5}

Kontrollér altid valgfrie værdier, før du bruger dem.

Brug type assertions (as) kun som sidste udvej.

Lad os derefter se på punktet om 'ikke at overforbruge type-påstande.'.

Type assertion omgår midlertidigt TypeScripts typekontrol for at erklære: 'Jeg ved, at denne værdi har denne type.'. Overforbrug af dem underminerer typesikkerhed.

1// Bad
2const value = input as string;

I denne kode opstår der ingen fejl, selvom den faktiske værdi ikke er en streng, hvilket kan føre til fejl under kørsel. Som vist i følgende kode bør du først vælge at kontrollere sikkert ved hjælp af type guards.

1// Good
2function isString(value: unknown): value is string {
3  return typeof value === "string";
4}
5
6if (isString(input)) {
7  console.log(input.toUpperCase());
8}

Type guards er en mekanisme til sikkert at bestemme en type, mens man kontrollerer den faktiske værdi. Ved at prioritere type guards over type assertions kan du lettere forhindre fejl under kørsel.

Stol ikke for meget på typeinferens ved returtyper.

Lad os derefter se på punktet om 'ikke at stole for meget på inferens for returtyper.'.

TypeScripts typeinferens er stærk, men det er mere sikkert at annotere returtyper for offentlige funktioner eksplicit. Dette minimerer de potentielle konsekvenser af fremtidige ændringer.

1// Bad
2function sum(a: number, b: number) {
3  return a + b;
4}

Angiv klart din hensigt, selv i små funktioner.

1// Good
2function sum(a: number, b: number): number {
3  return a + b;
4}

At skrive returtyper ud øger stabiliteten af dit API.

Håndtér inputs sikkert ved at bruge unknown.

Lad os derefter se på punktet om 'sikkert at acceptere ekstern input ved at bruge unknown.'.

For ekstern input såsom API’er, JSON eller brugerinput, brug unknown i stedet for any. Ved at gøre dette sikrer du, at alle værdier bliver valideret, hvilket opretholder typesikkerheden.

1// Bad
2function handleResponse(data: any) {
3  console.log(data.id);
4}

Sådan validerer du typer med unknown.

 1// Good
 2function handleResponse(data: unknown): void {
 3  if (
 4    typeof data === "object" &&
 5    data !== null &&
 6    "id" in data
 7  ) {
 8    console.log((data as { id: number }).id);
 9  }
10}

unknown kan ikke bruges som den er; det er en type, der kræver validering. Det er særligt effektivt, når man håndterer ekstern input.

Øg udtryksfuldhed ved at kombinere små typer.

Lad os derefter se på punktet om 'at øge udtryksfuldheden ved at kombinere små typer.'.

At definere store typer på én gang reducerer læsbarhed og vedligeholdelsesvenlighed. Opdel dine typer i meningsfulde enheder og kombiner dem efter behov.

 1type Id = number;
 2
 3type UserProfile = {
 4  id: Id;
 5  name: string;
 6};
 7
 8type UserWithStatus = UserProfile & {
 9  status: "active" | "inactive";
10};

At betragte typer som komponenter hjælper med at organisere dit design.

type og interface

Fordele ved interface

type og interface kan begge definere typer, men deres tiltænkte anvendelse og egenskaber adskiller sig. Ved at bruge dem til de rette roller bliver dine typedefinitioners formål tydeligere.

 1// Bad
 2type User = {
 3  id: number;
 4  name: string;
 5};
 6
 7type AdminUser = {
 8  id: number;
 9  name: string;
10  role: "admin";
11};

Hvis du duplikerer fælles dele som dette, bliver din kode sårbar over for ændringer.

1// Good
2interface User {
3  id: number;
4  name: string;
5}
6
7interface AdminUser extends User {
8  role: "admin";
9}

interface er ideelt til designs, der involverer udvidelse (extends), og er bedst egnet til at udtrykke 'formen' af objekter.

Fordele ved type

Omvendt er type mere udtryksfuld og velegnet til at håndtere union- og intersection-typer.

1// Good
2type Status = "idle" | "loading" | "success" | "error";
3
4type ApiResponse<T> =
5  | { status: "success"; data: T }
6  | { status: "error"; message: string };

type egner sig godt til at udtrykke tilstande, muligheder og kombinationer.

Retningslinjer for valg mellem type og interface

Som tommelfingerregel: brug interface til objektstrukturer og kontrakter, og type når du har brug for union, intersection eller typeoperationers udtryksfuldhed.

Begge fungerer på lignende måde, men det er vigtigt at vælge ud fra, hvad der bedst kommunikerer grundlaget for typens eksistens.

Betragt dine typer som dokumentation.

Til sidst lad os se på punktet om 'at skrive typer som dokumentation.'.

Gode typedefinitioner formidler mere information end kommentarer nogensinde kunne. Det er vigtigt at sigte efter en tilstand, hvor 'specifikationen kan forstås blot ved at se på typerne.'.

1type ApiError = {
2  code: number;
3  message: string;
4  retryable: boolean;
5};

På denne måde er en af TypeScripts store styrker, at typedefinitioner kan fungere som en form for specifikationsdokument.

Sammendrag

Bedste praksis i TypeScript handler ikke om at være overdrevent streng. Essensen er at tydeliggøre hensigten gennem typer og skrive kode, der er robust over for ændringer.

Ved at akkumulere små regler i daglig udvikling kan du opnå langsigtede effekter såsom 'nemmere gennemgang', 'færre fejl' og 'bedre forståelse for dig selv og andre i fremtiden.'.

Først, ved at tænke 'hvordan kan jeg udtrykke dette med typer?', vil du skrive kode af høj kvalitet i ægte TypeScript-stil.

Du kan følge med i ovenstående artikel ved hjælp af Visual Studio Code på vores YouTube-kanal. Husk også at tjekke YouTube-kanalen.

YouTube Video