Typy użytkowe w TypeScript

Typy użytkowe w TypeScript

Ten artykuł wyjaśnia typy użytkowe w TypeScript.

YouTube Video

Typy użytkowe w TypeScript

Typy użytkowe w TypeScript to wygodne narzędzia do tworzenia nowych typów na podstawie istniejących typów. Umożliwia to bardziej elastyczne definiowanie typów oraz zwiększa możliwość ponownego wykorzystania kodu. Tutaj szczegółowo wyjaśnimy najczęściej używane typy użytkowe i omówimy, jak używać każdego z nich na przykładach kodu.

Partial<T>

Partial<T> sprawia, że wszystkie właściwości typu obiektu są opcjonalne (pozwala na undefined). Jest to przydatne, gdy chcesz używać tylko niektórych właściwości, które posiada oryginalny typ.

 1interface User {
 2  id: number;
 3  name: string;
 4  age: number;
 5}
 6
 7function updateUser(user: Partial<User>) {
 8  console.log(user);
 9}
10
11updateUser({ name: "Alice" }); // Updates only 'name'

Wyjaśnienie:

W powyższym przykładzie użycie Partial<User> sprawia, że wszystkie właściwości typu User są opcjonalne. Dlatego w funkcji updateUser możesz przekazać tylko podzbiór właściwości.

Required<T>

Required<T> sprawia, że wszystkie właściwości, w tym opcjonalne, stają się wymagane. Używa się go, gdy chcesz, aby opcjonalne właściwości stały się wymagane.

 1interface User {
 2  id: number;
 3  name?: string;
 4  age?: number;
 5}
 6
 7function createUser(user: Required<User>) {
 8  console.log(user);
 9}
10
11// createUser({ id: 1 }); // Error: 'name' and 'age' are required
12createUser({ id: 1, name: "Alice", age: 25 });

Wyjaśnienie:

Użycie Required<User> powoduje, że właściwości, takie jak name i age, są traktowane jako wymagane.

Readonly<T>

Readonly<T> sprawia, że wszystkie właściwości obiektu są tylko do odczytu. Chroni to przed zmianą wartości obiektu.

 1interface User {
 2  id: number;
 3  name: string;
 4}
 5
 6const user: Readonly<User> = {
 7  id: 1,
 8  name: "Alice"
 9};
10
11// user.id = 2; // Error: 'id' is read-only
12console.log(user);

Wyjaśnienie:

Używając Readonly<T>, możesz chronić właściwości obiektu przed modyfikacją. Jest to skuteczne, gdy chcesz zapobiec przypadkowej modyfikacji danych podczas tworzenia oprogramowania.

Record<K, T>

Record<K, T> tworzy typ mapy ze zdefiniowanymi typami kluczy i wartości. K to typ kluczy (np. string lub number), a T to typ wartości.

 1type Roles = "admin" | "user" | "guest";
 2interface Permissions {
 3  read: boolean;
 4  write: boolean;
 5}
 6
 7const rolePermissions: Record<Roles, Permissions> = {
 8  admin: { read: true, write: true },
 9  user: { read: true, write: false },
10  guest: { read: false, write: false },
11};
12
13console.log(rolePermissions);

Wyjaśnienie:

Record<K, T> jest przydatne, gdy chcesz zdefiniować pary klucz-wartość. W powyższym przykładzie uprawnienia są definiowane na podstawie ról użytkowników.

Pick<T, K>

Pick<T, K> wyodrębnia tylko określone właściwości z typu obiektu. Możesz utworzyć nowy typ, wyodrębniając tylko potrzebne właściwości.

 1interface User {
 2  id: number;
 3  name: string;
 4  age: number;
 5}
 6
 7type UserSummary = Pick<User, "id" | "name">;
 8
 9const summary: UserSummary = {
10  id: 1,
11  name: "Alice"
12};
13
14console.log(summary);

Wyjaśnienie:

Używając Pick<T, K>, możesz wyodrębnić określone właściwości z typu obiektu i traktować je jako nowy typ. Na przykład w powyższym przykładzie wyodrębniono tylko id i name.

Omit<T, K>

Omit<T, K> wyklucza określone właściwości z typu obiektu. Jest to operacja odwrotna do Pick.

 1interface User {
 2  id: number;
 3  name: string;
 4  age: number;
 5  email: string;
 6}
 7
 8type UserWithoutEmail = Omit<User, "email">;
 9
10const userWithoutEmail: UserWithoutEmail = {
11  id: 1,
12  name: "Alice",
13  age: 25
14};
15
16console.log(userWithoutEmail);

Wyjaśnienie:

Używając Omit<T, K>, można utworzyć nowy typ, wykluczając określone właściwości. W powyższym przykładzie właściwość email jest wykluczona.

Exclude<T, U>

Exclude<T, U> tworzy nowy typ poprzez usunięcie typu U z typu unii T. Jest używany, gdy chcesz usunąć określony typ.

1type Status = "active" | "inactive" | "pending";
2type ExcludedStatus = Exclude<Status, "pending">;
3
4const status: ExcludedStatus = "active"; // "pending" is excluded, so it cannot be chosen
5console.log(status);

Wyjaśnienie:

Używając Exclude<T, U>, możesz usunąć niepotrzebne typy z typu unii. W powyższym przykładzie, ponieważ "pending" jest wykluczony, można wybrać tylko "active" lub "inactive".

Extract<T, U>

Extract<T, U> wyciąga części, które pasują do typu U w obrębie typu unii T. Jest przydatny, gdy chcesz wyodrębnić tylko określony typ.

1type Status = "active" | "inactive" | "pending";
2type ActiveStatus = Extract<Status, "active" | "pending">;
3
4const status: ActiveStatus = "active"; // "inactive" cannot be chosen
5console.log(status);

Wyjaśnienie:

Extract<T, U> wykonuje operację odwrotną do Exclude. W powyższym przykładzie można wybrać tylko "active" i "pending".

NonNullable<T>

NonNullable<T> tworzy typ z wykluczonymi null i undefined. Jest przydatny, gdy chcesz wykluczyć te wartości z typów opcjonalnych.

1type UserName = string | null | undefined;
2type ValidUserName = NonNullable<UserName>;
3
4const name: ValidUserName = "Alice"; // null and undefined cannot be chosen
5console.log(name);

Wyjaśnienie:

NonNullable<T> wyklucza null i undefined z typu, który je zawiera. Jest to przydatne, gdy chcesz upewnić się, że wartość na pewno istnieje.

Wnioski

Typy użytkowe TypeScript są potężnym narzędziem do tworzenia bardziej zwięzłych i elastycznych definicji typów. Zrozumienie i odpowiednie używanie podstawowych typów użytkowych, takich jak Partial, Required, Readonly, Record itp., może zwiększyć możliwość ponownego wykorzystania i utrzymania kodu. Opanowanie tych typów pozwala na bardziej solidne i bezpieczne definicje typów, co umożliwia wydajniejszy rozwój.

Operator keyof w TypeScript

Operator keyof w TypeScript służy do pobierania wszystkich nazw właściwości danego typu obiektu. Za pomocą tego operatora można uzyskać klucze typu obiektu jako typ unii. Jest to niezwykle przydatne przy pisaniu kodu z zachowaniem bezpieczeństwa typów.

Podstawowe użycie

1interface Person {
2    name: string;
3    age: number;
4    email: string;
5}
6
7// Use keyof to get the property names of Person
8type PersonKeys = keyof Person; // "name" | "age" | "email"

Przykładowe użycie

  1. Używanie w argumentach funkcji

    Możesz użyć keyof, aby zdefiniować funkcję z typami opartymi na określonych właściwościach obiektu.

1function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
2    return obj[key];
3}
4
5const person: Person = { name: "Alice", age: 30, email: "alice@example.com" };
6const name = getProperty(person, "name"); // type is string
7const age = getProperty(person, "age");   // type is number
  1. Wzmacnianie ograniczeń typów

    Korzystając z keyof, możesz zapewnić, że klucze przekazane do funkcji zostaną zweryfikowane w czasie kompilacji.

1// Passing an invalid property name results in an error
2const invalid = getProperty(person, "invalidKey"); // Error

Podsumowanie

  • Operator keyof służy do pobierania nazw wszystkich właściwości typu obiektu.
  • Możesz uzyskać nazwy właściwości jako typ unii, osiągając bezpieczeństwo typów w kodzie.
  • Stosując go w argumentach funkcji, można ograniczyć funkcję do przyjmowania tylko poprawnych nazw właściwości.

W ten sposób operator keyof zwiększa bezpieczeństwo typów w TypeScript i pomaga pisać bardziej niezawodny kod.

Możesz śledzić ten artykuł, korzystając z Visual Studio Code na naszym kanale YouTube. Proszę również sprawdzić nasz kanał YouTube.

YouTube Video