|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: Czy wiesz, że TypeScript ma typ bezpieczniejszy niż Any? |
| 4 | +description: "" |
| 5 | +date: 2025-12-04T06:00:00+01:00 |
| 6 | +published: true |
| 7 | +didyouknow: false |
| 8 | +lang: pl |
| 9 | +author: wstolarski |
| 10 | +image: /assets/img/posts/2025-12-04-czy-wiesz-ze-typescript-ma-typ-bezpieczniejszy-niz-any/thumbnail.webp |
| 11 | +tags: |
| 12 | +- typescript |
| 13 | +--- |
| 14 | + |
| 15 | +W TypeScript, poza `string` czy `number`, mamy też kilka specjalnych typów do obsługi sytuacji, gdy nie znamy typu danych. Przyjrzyjmy się im z bliska. |
| 16 | + |
| 17 | +## Any i unknown – podobieństwa i różnice |
| 18 | + |
| 19 | +Na pierwszy rzut oka typy `any` i `unknown` wyglądają podobnie. Oba pozwalają przypisać do siebie dowolną wartość. To, co możemy potem z tym zrobić, nieco się różni. |
| 20 | + |
| 21 | +### Typ any – "nie wiemy i nie interesuje nas to" |
| 22 | +Typ `any` wyłącza sprawdzanie typów dla danej zmiennej w TypeScript. Kompilator nie sprawdza, co przypisujemy i jak używamy tej zmiennej. Możemy zrobić z nią wszystko, a ewentualny błąd zobaczymy dopiero w trakcie działania aplikacji. |
| 23 | + |
| 24 | +```typescript |
| 25 | +let drawer: any = "Old watch"; |
| 26 | +console.log(drawer.substring(6)); // Działa |
| 27 | + |
| 28 | +drawer = { keys: 3 }; |
| 29 | +// Kompilator nie zgłasza błędu, ale runtime już tak: |
| 30 | +console.log(drawer.substring(6)); // TypeError: drawer.substring is not a function |
| 31 | +``` |
| 32 | + |
| 33 | +### Typ unknown – "nie wiemy, ale sprawdzimy" |
| 34 | +Typ `unknown` jest bezpieczniejszą alternatywą dla `any`. Możemy przypisać dowolną wartość, ale TypeScript wymaga, by przed użyciem sprawdzić typ tej zmiennej. Dzięki temu nie popełnimy błędu w runtime. |
| 35 | + |
| 36 | +```typescript |
| 37 | +let box: unknown; |
| 38 | +box = "keyboard"; |
| 39 | +console.log(box.toUpperCase()); |
| 40 | +// TypeScript zgłasza błąd kompilacji: 'box' is of type 'unknown'. |
| 41 | + |
| 42 | +// Rozwiązaniem problemu jest sprawdzenie typu: |
| 43 | +if (typeof box === "string") { |
| 44 | + console.log(box.toUpperCase()); |
| 45 | +} |
| 46 | +``` |
| 47 | + |
| 48 | +## Typ never – "to się nigdy nie wydarzy" |
| 49 | +Typ `never` oznacza, że funkcja nigdy nie zakończy swojego działania normalnie (np. zawsze rzuca wyjątek lub wpada w nieskończoną pętlę). |
| 50 | +Nie należy mylić tego z `void` (funkcja się kończy, ale nic nie zwraca). `never` sygnalizuje, że kod jest nieosiągalny. |
| 51 | + |
| 52 | +### Przypadki użycia |
| 53 | +Spójrzmy na kilka przykładów użycia typu `never`: |
| 54 | +#### Funkcja, która zawsze rzuca błąd |
| 55 | +```typescript |
| 56 | +function error(message: string): never { |
| 57 | + throw new Error(message); |
| 58 | +} |
| 59 | + |
| 60 | +function fail(): never { |
| 61 | + return error("Something failed"); |
| 62 | +} |
| 63 | +``` |
| 64 | +Funkcja `error()` nigdy nie zwraca wartości. Zawsze zatrzymuje program, rzucając błędem. |
| 65 | + |
| 66 | +#### Funkcja z nieskończoną pętlą |
| 67 | +```typescript |
| 68 | +function infiniteLoop(): never { |
| 69 | + while (true) {} |
| 70 | +} |
| 71 | +``` |
| 72 | +Funkcja wpada w pętlę, z której nie ma wyjścia. Nigdy nie kończy swojego działania. |
| 73 | + |
| 74 | +#### Sprawdzanie kompletności obsługi wariantów (Exhaustive Check) |
| 75 | +```typescript |
| 76 | +type Shape = 'circle' | 'square'; |
| 77 | + |
| 78 | +function getArea(shape: Shape): number { |
| 79 | + switch (shape) { |
| 80 | + case 'circle': |
| 81 | + return Math.PI * 2; |
| 82 | + case 'square': |
| 83 | + return 4; |
| 84 | + default: |
| 85 | + // Jeśli dodamy nowy kształt, taki jak 'triangle', |
| 86 | + // do typu, TypeScript wyświetli tutaj błąd, |
| 87 | + // ponieważ nowy kształt nie może być przypisany do never |
| 88 | + const exhaustiveCheck: never = shape; |
| 89 | + return exhaustiveCheck; |
| 90 | + } |
| 91 | +} |
| 92 | +``` |
| 93 | +Typ `never` świetnie pilnuje, czy switch obsługuje wszystkie warianty typu. |
| 94 | + |
| 95 | +## Kiedy i co wybrać? |
| 96 | +- **unknown** – używajmy, gdy nie znamy typu danych (np. odpowiedź z API). To bezpieczny wybór, który wymusza weryfikację typu przed użyciem. |
| 97 | +- **any** – najlepiej unikajmy `any` całkowicie. Wyłącza ono sprawdzanie typów, co jest głównym celem TypeScriptu. Włączmy w konfiguracji tryb `strict`, a dla nieznanych typów stosujmy bezpieczniejszy `unknown`. |
| 98 | +- **never** – używajmy, by zaznaczyć, że dany kod jest nieosiągalny. Świetne do funkcji rzucających błędy i do pilnowania kompletności switcha. |
| 99 | + |
| 100 | +## Dokumentacja |
| 101 | +- [TypeScript: any](https://www.typescriptlang.org/docs/handbook/basic-types.html#any) |
| 102 | +- [TypeScript: unknown](https://www.typescriptlang.org/docs/handbook/basic-types.html#unknown) |
| 103 | +- [TypeScript: never](https://www.typescriptlang.org/docs/handbook/basic-types.html#never) |
| 104 | +- [Mimo: never](https://mimo.org/glossary/typescript/never) |
0 commit comments