Функція TypeScript 5.3, про яку вам не розповіли
20 листопада 2023 року команда TypeScript випустила TS 5.3.
Одна з найважливіших змін у TypeScript 5.3 не була згадана у примітках до релізу.
Швидкий приклад коду
// Це було б помилкою у 5.2, але дозволено у 5.3!
const array = ["a", "b", "c"] as const satisfies string[];
const returnWhatIPassIn = <const T extends any[]>(t: T) => {
return t;
};
// результат - any[] в TS 5.2, но ['a', 'b', 'c'] в 5.3
const result = returnWhatIPassIn(["a", "b", "c"]);
Повне пояснення
Робота з масивами, доступними для читання, TS може іноді доставляти деякі незручності.
Допустимо, ви хочете оголосити масив роутів як const.
Це дозволить вам повторно використовувати роути, оголошені типу.
const arrayOfRoutes = [
{ path: "/home", component: Home },
{ path: "/about", component: About },
] as const;
// type Route = "/home" | "/about"
type Route = (typeof arrayOfRoutes)[number]["path"];
Але якщо ви хочете переконатися, що масив arrayOfRoutes
відповідає певному типу?
Для цього можна використовувати satisfies.
const arrayOfRoutes = [
{ path: "/home", component: Home },
{ path: "/about", component: About },
] as const satisfies {
path: string;
component: React.FC;
}[];
// Тип є "readonly" і не може бути
// присвоєний типу, що змінюється
Єдина проблема полягає в тому, що TypeScript 5.2 це призведе до помилки! Але чому?
Масиви, доступні для читання, та масиви, що змінюються.
Це тому, що arrayOfRoutes
доступний лише для читання, а ви не можете використовувати масив, доступний для зміни, для масиву, доступного для читання.
Тому виправлення полягало в тому, щоб зробити тип, який ми покриваємо, масивом readonly
:
const arrayOfRoutes = [
{ path: "/home", component: Home },
{ path: "/about", component: About },
] as const satisfies readonly {
path: string;
component: React.FC;
}[];
// Помилок більше немає!
Тепер, коли ми використовуємо масив, доступний лише читання, TypeScript щасливий.
Параметри типу Const
Те саме відбувається і при використанні параметрів типу const
, але ще більш згубно.
У цьому випадку const
виводить річ, передану в T
, ніби вона була const
.
Але якщо ви спробуєте обмежити його масивом, це не спрацює!
const returnWhatIPassIn = <const T extends any[]>(t: T) => {
return t;
};
// Результат: any[] в TS 5.2!
const result = returnWhatIPassIn(["a", "b", "c"]);
До версії TS 5.3 виправлення полягало в додаванні readonly
до параметра type
:
const returnWhatIPassIn = <const T extends readonly any[]>(
t: T
) => {
return t;
};
// Результат: ['a', 'b', 'c']!
const result = returnWhatIPassIn(["a", "b", "c"]);
Але це виправлення було важко знайти і вимагало глибоких знань про те, як працюють параметри типу const
.
Як TypeScript 5.3 виправив ситуацію
Починаючи з версії 5.3 TypeScript пом’якшив правила роботи з масивами, доступними для читання.
У цих двох ситуаціях TypeScript діє ефективніше.
Ключове слово satisfies
тепер дозволяє передавати масиви з readonly
:
// Це було б помилкою у 5.2, але дозволено у 5.3!
// const array: ["a", "b", "c"]
const array = ["a", "b", "c"] as const satisfies string[];
Параметри типу Const
тепер визначають переданий тип замість того, щоб за промовчанням використовувати свої обмеження:
const returnWhatIPassIn = <const T extends any[]>(t: T) => {
return t;
};
// Результат: any[] в TS 5.2, но ['a', 'b', 'c'] в 5.3
// const result: ["a", "b", "c"]
const result = returnWhatIPassIn(["a", "b", "c"]);
Зверніть увагу на невелику різницю! Якби ви вказали readonly
string[]
замість string[]
, то отримали б назад масив readonly.
Тому вам все одно потрібно вказати readonly
, якщо ви хочете отримати назад масив, доступний для читання.
// Це було б помилкою у 5.2, але дозволено у 5.3!
// const array: readonly ["a", "b", "c"]
const array = [
"a",
"b",
"c",
] as const satisfies readonly string[];
const returnWhatIPassIn = <const T extends readonly any[]>(
t: T
) => {
return t;
};
// результат - any[] в TS 5.2, но ['a', 'b', 'c'] в 5.3
// const result: readonly ["a", "b", "c"]
const result = returnWhatIPassIn(["a", "b", "c"]);
Але це значне поліпшення, що робить роботу з параметрами типу const, так і з задовольнячими набагато простіше.
TypeScript – ви повинні кричати про такі речі!
Переклад статті “The TypeScript 5.3 Feature They Didn’t Tell You About“