Typescript: Required<Type>
23.02.2022
Typescript: Required<Type>

​​​​​​​V úvodním článku našeho seriálu o TypeScriptu Efektivní TypeScript​​​​ jsme se zaměřili na generický transformační typ Partial.
Jeho opakem je Required​, ale stejně jako Partial je aplikován pouze na položky na nejvyšší úrovni.

Pojďme si dát tentokrát za cíl vytvoření nového typu z aktuálního tak, že nově vytvořený typ má veškeré položky povinné.

Mějme typový alias User, jehož definice je následující:

   type User = {
  firstName?: string;
  lastName?: string;
  age?: number;
} 

výsledkem následujícího přiřazení

   
type RequiredUser = Required<User>;

je typový alias se všemi položkami povinnými.

   type User = {
  firstName: string;
  lastName: string;
  age: number;
} 

Pro demonstraci toho, že Required označí jako povinné pouze položky na nejvyšší úrovni, si zadefinujme adresu jako

   type Address = {
  street?: string;
  city?: string;
}

a uživatele včetně adresy následovně:

   type User = {
  firstName?: string;
  lastName?: string;
  age?: number;
  address?: Address;
}

Výsledkem přiřazení​

   type RequiredUserNoDeep = Required<User>;

pak je

   type User = {
  firstName: string;
  lastName: string;
  age: number;
  address: {
    street?: string;
    city?: string;
  }
}

Jinými slovy, adresa sama o sobě je povinná, jednotlivé její položky však nikoli.

Pro úplnost se ještě pojďme podívat na implementaci a trochu si ji v krátkosti rozebrat:

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

Implemetace výše mapuje každou položku původního typu dle daného předpisu. V našem případě je odstraněn z každého klíče původního typu Elvis operátor “?“ a z volitelné položky je učiněna položka povinná.

V porovnání s Partial, probíraném v předešlém článku, a jehož implementace vykonává pravý opak, každý klíč původního typu označuje jako volitelný.

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

Je dobré si pamatovat, že pokud použijeme typ Required v projektu, kde TypeScriptový překladač má nastavenu hodnotu strictNullChecks: true, pak aplikace typu Required neodstraní pouze nepovinnost dané položky, ale též undefined. Pojďme si to ukázat na příkladu, definujme uživatele následovně:

   type User = {
  firstName: string;
  lastName?: string;
  thirdName?: string | undefined;
  age: number;
}

a proveďme následující přiřazení:​

   type RequiredUser = Required<User>;

pak výsledný alias vypadá takto:

   type Required<User> = {
  firstName: string;
  lastName: string;
  thirdName: string;
  age: number;
}
jinými slovy, při použití původního typu User jsme byli schopni uložit hodno​tu undefined do proměnných lastName a thirdName
   let user: User = {
  firstName: 'Adam',
  lastName: undefined,
  thirdName: undefined,
  age: 30
}

zatímco po aplikaci Required již hodnotu undefined vložit do proměnných lastName a thirdName není povoleno a následující kód skončí chybou. Ušetřete si práce a mějte toto chování na paměti.

   ​let user: Required<User​> = {
  firstName: 'Adam',
  lastName: undefined,
  thirdName: undefined,
  age: 30
}

​​​Závěrem

Tentokrát jsme si ukázali, jak se standardně Required chová a také jsme se seznámili se situací, jak se jeho chování změní, když je parametr strictNullChecks nastaven na hodnotu true. Příště se zaměříme na Capitalize a Uncapitalize.

Václav Kandus