Typy przecięć (&, intersection types) pozwalają na połączenie kilku typów w jeden, który zyskuje wszystkie właściwości połączonych typów.
type Osoba = { name: string }; type Pracownik = { job: string }; type PracującaOsoba = Osoba & Pracownik; // { name: string; job: string } const po: PracującaOsoba = { name: "Leo", job: "Dev" };
Jest to wygodne przy kompozycji rozwijalnych kontraktów i budowaniu złożonych typów z prymitywów.
Jednak, jeśli przecięte zostaną niekompatybilne typy (np. type A = { foo: string } i type B = { foo: number }), otrzymujemy typ, który nie może być zainicjowany.
type A = { foo: string }; type B = { foo: number }; type C = A & B; // C = { foo: never }
Co się stanie, jeśli przecięniemy dwa typy, w których występuje to samo pole z niekompatybilnymi typami danych?
Odpowiedź: Otrzymamy pole z typem never, ponieważ wartość nie może być jednocześnie zarówno ciągiem, jak i liczbą. Taki typ nie może być poprawnie zrealizowany.
type T1 = { id: string }; type T2 = { id: number }; type T3 = T1 & T2; // { id: never }
Historia
W projekcie przecięto typy z różnych bibliotek, nie zauważając, że istnieją identyczne pola o różnych typach. W rezultacie otrzymywano nieprzewidziany typ 'nieosiągalny' (never), co prowadziło do niemożności stworzenia poprawnego obiektu do przesłania do API.
Historia
Programiście potrzebne było 'połączenie' typów DTO i encji domenowej. W przecięciu znalazły się dwa niekompatybilne właściwości, a próba użycia uzyskanego typu powodowała niejednoznaczne błędy kompilacji. Programista spędził czas na debugu, zanim zrozumiał przyczynę.
Historia
W jednym z mikroserwisów ogłoszono typ przecięty do opisu ciała zapytania. W wyniku zmiany API jedna z właściwości zyskała inny typ, a nowe zmiany od razu nie prowadziły do błędu kompilacji — problemy pojawiły się dopiero w czasie działania po wdrożeniu.