Satisfies — Satysfakcjonujący operator języka TypeScript

  • typescript

Microsoft nie zwalnia tempa i dostarcza do naszego ukochanego TypeScripta nowe funkcjonalności, które usprawniają codzienny development. Nowy operator satisfies pozwoli otypować strukturę danych w taki sam sposób jak standardowa asercja, lecz interpreter będzie nadal w stanie wywnioskować właściwą zawartość, co sprawia, że pozbędziemy się z kodu niepotrzebnych warunków czy type guardów.

Przejdźmy od razu do przykładu:

const openings = {
  monday: ['8:00', '16:00'],
  tuesday: ['9:00', '17:00'],
  wendesday: ['9:00', '17:00'],
  thursday: ['9:00', '17:00'],
  friday: ['9:00', '17:00'],
  saturday: null,
  sunday: null,
}

Jest to obiekt zawierający godziny otwarcia sklepu dla danych dni tygodnia. Wartość null znaczy, że sklep w tym dniu jest zamknięty. Chcąc otypować taką strukturę danych, możemy wykorzystać utility type Record:

type Days = 'monday' | 'tuesday' | 'wendesday' | 'thursday' | 'friday' | 'saturday' | 'sunday'
type Hours = [string, string]

type Openings = Record<Days, Hours | null>

const openings: Openings = {
  monday: ['8:00', '16:00'],
  tuesday: ['9:00', '17:00'],
  wendesday: ['9:00', '17:00'],
  thursday: ['9:00', '17:00'],
  friday: ['9:00', '17:00'],
  saturday: null,
  sunday: null,
}

W tym momencie obiekt openings ma przypisany konkretny typ. Na pierwszy rzut oka nie wygląda to problematycznie, jednak gdy będziemy chcieli odwołać się do jakiegokolwiek dnia, aby wykonać na nim operację, otrzymamy błąd, że dana wartość może być nullem.

openings.friday.join(' - ')
// => 'openings.monday' is possibly 'null'.(18047)

Dzieje się tak dlatego, że TypeScript nie potrafi się domyślić, która wartość jest jakiego typu. Luźno tylko wskazuje, że kluczami muszą być wartości tekstowe zdefiniowane w typie Days, natomiast ich wartością może być null, lub Hours. Resztę walidacji musimy zrobić samodzielnie, warunkując kod lub pisząc type guardy.

Wykorzystując satisfies, TypeScript nie straci informacji o rzeczywistej zawartości obiektu, lecz jedynie dopilnuje, żeby typ danych się zgadzał podczas definicji.

type Days = 'monday' | 'tuesday' | 'wendesday' | 'thursday' | 'friday' | 'saturday' | 'sunday';
type Hours = [string, string];

type Openings = Record<Days, Hours | null>

const openings = {
  'monday': ['8:00', '16:00'],
  'tuesday': ['9:00', '17:00'],
  'wendesday': ['9:00', '17:00'],
  'thursday': ['9:00', '17:00'],
  'friday': ['9:00', '17:00'],
  'saturday': null,
  'sunday': null,
} satisfies Openings;

openings.friday.join(' - ');
openings.saturday.
// => 'openings.sunday' is possibly 'null'.

Jak widać inferencja zadziałała prawidłowo ponieważ na piątku możemy wywołać metodę join(), a w sobotę co najwyżej będziemy mogli pocałować klamkę.

Czujesz się usatysfakcjonowany?

Bez wątpienia operator satisfies poprawi nasz komfort pracy podczas typowania i walidowania danych. Dużo obszerniejsze omówienie operatora możesz znaleźć w utworzonym Issue z proposalem.

TypeScript 4.9 wprowadził jeszcze kilka przydatnych funkcjonalności, do których zapoznania odsyłam na oficjalną stronę.

Zobacz także