6 августа сего года Microsoft объявила о выходе релиз-кандидата TypeScript 4.0. Там появилась поддержка кортежей с маркированными элементами (Labeled Tuple Elements). А это — именно то, появления чего я ждал в TypeScript.
Наверху — аргументы, которым назначены содержательные метки. Внизу — аргументы с бесполезными именами
Почему я этого ждал? Объясню это на примере разработки функции.
Обобщённый интерфейс, поддерживающий гибкую работу с аргументами
Вот — упрощённый пример. Он основан на использовании интерфейса IQuery
. Интерфейс предназначен для описания характеристик функций, выполняющих запросы на получение чего-либо. Он всегда возвращает промис и принимает дженерик, описывающий то, что возвращает промис (TReturn
). Этот интерфейс достаточно гибок, им можно использоваться при создании функций, не принимающих никаких аргументов, или принимающих неизвестное количество аргументов (UParams extends any[] = []
).
interface IQuery<TReturn, UParams extends any[] = []> {
(...args: UParams): Promise<TReturn>
}
Исследуемая функция: findSongAlbum()
Мы, используя этот интерфейс, напишем функцию, которая ищет музыкальные альбомы по названию композиции (title
) и по исполнителю (artist
). Она возвращает промис, который выдаёт единственный объект типа Album
:
type Album = {
title: string
}
Без использования TypeScript код подобной функции мог бы выглядеть так:
const findSongAlbum = (title, artist) => {
// код загрузки данных...
const albumName = '1989';
return Promise.resolve({
title: albumName
});
}
Если же написать такую функцию на TypeScript и воспользоваться при этом интерфейсом IQuery
, то в качестве первого дженерик-параметра ей нужно передать тип Album
. Это позволяет обеспечить то, что форма того, что возвращает промис, всегда будет соответствовать типу Album
.
const findSongAlbum: IQuery<Album> = (title, artist) => {
// код загрузки данных...
const albumName = '1989';
return Promise.resolve({
title: albumName
});
}
Код, который писали до TypeScript 4.0
При разработке нашей функции ещё нужно объявить параметры и указать то, какие типы они имеют. В данном случае title
и artist
— это строки. Объявим новый тип, Params
, и передадим его в качестве второго типа для IQuery
.
В том примере, который написан без использования новых возможностей TypeScript 4.0, Params
будет представлен списком типов. Каждый элемент этого списка определяет тип аргумента. Делается это в том же порядке, в котором аргументы располагаются при объявлении функции. Это — пример использования кортежей.
type Params: [string, string]
const findSongAlbum: IQuery<Album, Params> = (title, artist) => {
// код загрузки данных...
const albumName = '1989';
return Promise.resolve({
title: albumName
});
}
Анализируя тип Params
, можно узнать о том, что его первый элемент, string
, назначает тип string
первому аргументу, то есть — title
. Второй аргумент, тоже выглядящий как string
, естественно, следуя тому же ходу рассуждений, назначает тип string
второму аргументу — artist
. Это обеспечит типобезопасную работу со списком аргументов.
Попробуем поработать с этой функцией.
В подсказках к findSongAlbum() выводятся бессмысленные метки аргументов
К сожалению, подобный подход к использованию кортежей не даёт нам полезных и способствующих написанию надёжного кода имён (меток) аргументов при работе с функцией. Вместо этого нам сообщают о том, что аргументами функции являются args_0: string, args_1: string
. Из этого сообщения я могу узнать, например, лишь о том, что первый аргумент должен иметь тип string
. Метка arg_0
не даёт мне сведений о том, что первым параметром функции должно быть название (title
) музыкальной композиции, которую я ищу.
Код, в котором используются возможности TypeScript 4.0
Теперь, с выходом релиз-кандидата TypeScript 4.0, в нашем распоряжении оказываются кортежи с маркированными элементами. Их мы можем использовать для того чтобы описывать не только тип, но и смысловое содержание списков параметров функций.
Теперь каждый элемент типа Params
будет снабжён меткой, которая будет выводиться в IDE при использовании функции findSongAlbum
:
type Params: [title: string, artist: string]
const findSongAlbum: IQuery<Album, Params> = (title, artist) => {
// код загрузки данных...
const albumName = '1989';
return Promise.resolve({
title: albumName
});
}
А вот как выглядит работа с этой функцией.
В подсказках к findSongAlbum() выводятся метки аргументов, позволяющие понять смысл этих аргументов, что весьма полезно
Как видите, теперь, вместо подсказки вида arg_0: string
нам дают подсказку title: string
. А это значит, что мы теперь знаем не только о том, что функции надо передать строку, но и о том, что именно должна содержать эта строка.
Чего вам особенно не хватает в TypeScript?
Автор: ru_vds