As const у Typescript

TypeScript

У розробці часто виникають ситуації, коли точність типів та небажання допускати неясності в коді стають першорядними завданнями. У таких випадках розробникам доводиться шукати інструменти, що надають максимальну ясність та строгість у визначенні даних. Один із таких інструментів — ключове слово as const. У цій статті ми розглянемо, як as constможе підвищити рівень суворості та передбачуваності, а також розглянемо практичні приклади його використання для створення незмінних та точних типів.

Докладніше про “as const”

Коли ви використовуєте as const змінну або значення, TypeScript уточнює тип цієї змінної до її точного значення або комбінації літеральних типів. Це часто використовується для створення незмінних значень та гарантування того, що TypeScript розглядатиме значення як конкретні літерали, а не розширюватиме типи.

Приклад :

Уявіть, що нам потрібно написати функцію для відкриття вхідних дверей до будинку. Пишемо функцію, яка приймає параметром ключ, та проводить з ним будь-які операції.

const wallet = {
  key: "open_door_pls"
}

const openDoor = (key: "open_door_pls") => {
  //...
}

Але коли ми намагаємося використовувати функцію openDoor з ключем з нашого гаманця, чомусь відбувається таке:

const wallet = {
  key: "open_door_pls"
}

const openDoor = (key: "open_door_pls") => {
  //...
}

openDoor(wallet.key) // ERROR: Argument of type 'string' is not assignable to parameter of type '"open_door_pls"'

Чому ж ми потрапили до такої ситуації?

Вся справа в тому, що wallet.key у нас ніяк не прив’язаний до значення "open_door_pls”, і по суті є просто елементом з типом string, значення якого можна легко змінити на інше:

const wallet = {
  key: "open_door_pls"
}

wallet.key = "cucumber" // код отрабатывает без ошибок

Щоб уникнути такої поведінки, і зробити всі елементи wallet повноцінними, незмінними ( readonly) значеннями, ми можемо скористатися конструкцією as const:

const wallet = {
  key: "open_door_pls"
} as const

wallet.key = "cucumber" // ERROR: Cannot assign to 'key' because it is a read-only property.

Елементи wallet прив’язалися до своїх значень і тепер мають прапор readonly.

Що зрештою вирішило нашу проблему з параметром функції openDoor:

const wallet = {
  key: "open_door_pls"
} as const;

const openDoor = (key: "open_door_pls") => {
  //...
};

openDoor(wallet.key) // код отрабатывает без ошибок

Чому не Object.freeze()?

Проблема Object.freeze() полягає в тому, що після заморожування об’єкта readonly присвоюється лише елементам на верхньому рівні вкладеності.

const car = Object.freeze({
  name: "Porshe Cayenne",
  equipment:{
    engine: "MDC.AB"
  }
});

car.equipment.engine = "F8CV";

При використанні as constкомпілятора на будь-якому рівні вкладеності вкаже, що програміст намагається змінити константу.

const car = {
  name: "Porshe Cayenne",
  equipment:{
    engine: "MDC.AB"
  }
} as const;

car.equipment.engine = "F8CV"; // ERROR: Cannot assign to 'engine' because it is a read-only property.

Заміна enum-ам?

as constчудово підходить як альтернатива enum.

Про мінуси enum можна докладно почитати у цій статті.

Приклад переходу коду enumз as const:

Код, з використанням enum:

enum Wallet {
  KEY = "open_door_pls"
};

const openDoor = (key: "open_door_pls") => {
  //...
};

openDoor(Wallet.KEY)

Код, переписаний на as const:

const wallet = {
  key: "open_door_pls"
} as const;

const openDoor = (key: "open_door_pls") =>{
  //...
};

openDoor(wallet.key);

Ще одна дійсно крута особливість as const полягає в тому, що використання as const дозволяє бути дуже гнучким у поводженні з ключовим об’єктом:

const friendsDict = {
  Alfred: "101 Pine Road, Toronto, ON M5A 1A1, Canada",
  Liam: "777 Sycamore Lane, Tokyo, 100-0001, Japan",
  Mia: "666 Willow Street, Paris, 75001, France",
} as const;

type FriendName = keyof typeof friendsDict; // "Alfred" | "Liam" | "Mia"
type FriendAddress = (typeof friendsDict)[keyof typeof friendsDict];
//"101 Pine Road, Toronto, ON M5A 1A1, Canada" | "777 Sycamore Lane, Tokyo, 100-0001, Japan" | "666 Willow Street, Paris, 75001, France"

Резюмуючи

Ми розглянули конструкцію as const у TypeScript та її роль у створенні більш строгих та передбачуваних типів даних. Сподіваюся, що ця стаття допомогла вам краще зрозуміти, як використання as const може підвищити рівень безпеки та ясності вашого коду.

Таким чином, впровадження as const у ваш код може бути ключем до полегшення його підтримки у майбутньому та зменшення ймовірності помилок. Користуйтеся цим інструментом з розумом, і ваш код стане чистішим, надійнішим та легко підтримуваним!

Джерело