Mega rzecz, którą znalazłem na jakimś blogu. Trudno to będzie opisać bez przykładu, więc powiem tak – magia TSa, lekcja jak najbardziej obowiązkowa. Zaczynamy.

Blog jakby kto pytał nazywa się type of web. I stamtąd pochodzi przykład i tam odsyłam.

Ok, weźmy sobie takie coś:

type Model321 = {
    name: string;
    age: number;
  
    save(): Promise<void>;
  };

Teraz odrobina bełkotu:

type FieldsNames<T extends object> = {
    [K in keyof T]: T[K] extends Function ? never : K;
  };

Teraz zobaczymy, co ten bełkot nam wyprodukuje:

type FieldsNames<T extends object> = {
    [K in keyof T]: T[K] extends Function ? never : K;
  };

type ModelFields = FieldsNames<Model321>;
  
//   type ModelFields = {
//     name: "name";
//     age: "age";
//     save: never;
// }

No niby ma sens. Pytanie na co nam coś takiego. A teraz dodajmy takie coś:

type FieldsNames<T extends object> = {
    [K in keyof T]: T[K] extends Function ? never : K;
  }[keyof T];

„Takie coś” nawet nie wiem, czy ma swoją nazwę, w dokumentacji tego znaleźć nie mogłem. Pierwszy raz takiego TSa na oczy widzę. To tak, żebyśmy dobrze zrozumieli, co się stało:

type Model321 = {
    name: string;
    age: number;
  
    save(): Promise<void>;
  };

type FieldsNames<T extends object> = {
    [K in keyof T]: T[K] extends Function ? never : K;
  }[keyof T];

  type ModelFields = FieldsNames<Model321>;

//  type ModelFields = "name" | "age"

Czyli postawiliśmy warunek i po tym warunku wyciągnięto nazwy kluczy, które ten warunek spełniły. Wywaliło klucze, których typ to była funkcja.

Czyli teraz możemy zrobić sobie utility type, który wyciąga nam tylko pola (bez metod) i tworzy w oparciu o to typ:

type Model321 = {
    name: string;
    age: number;
  
    save(): Promise<void>;
  };

type FieldsNames<T extends object> = {
    [K in keyof T]: T[K] extends Function ? never : K;
  }[keyof T];

type OnlyFields<T extends object> = {
    [K in FieldsNames<T>]: T[K];
  };
  
type ModelFields = OnlyFields<Model321>;

// type ModelFields = {
//     name: string;
//     age: number;
// }

I tak wygląda nauka TSa. Pełno jest tutoriali, które godzinami cię będą uczyć „abstract keyword tworzy klasę abstrakcyjną zwierzątko”, z drugiej strony pełno złych przykładów na różnych portalach, wreszcie są i bardzo dobre.

Niestety wbrew temu co się mówi, nie ma dobrych (także płatnych) źródeł do nauki. Albo jest ich bardzo niewiele. Trzeba umieć szukać i kombinować z kodem.

Wkrótce więcej TSa.