#тип дня
Типом дня назначается вон тот в кожаной куртке. Да-да, о тебе говорю!
TL;DR: вычисленный тип функции с дженерик-аргументом можно сузить, декларируя тип как const.
Кроме шуток, разве тебя не бесит, что указываешь вот дженерик тип аргумента функции, производишь манипуляции над переданным объектом — а в ответ тебе вычисленный базовый тип?
Непонятно? Давай так:
Какой вычисленный тип получат first и second?
Очевидно, такой:
Но... это же довольно неудобно. А если мы схему валидируем, например? Или форму описываем. Или тесты пишем в конце-концов. Почему при заранее известном константном типе входных данных мы получаем вычисленную строку?
К счастью, начиная с TypeScript 5.0 можно объявлять дженерики как константные типы! Иначе говоря, работать с максимально узкими (narrow) типами. Это, собственно, аналог указания as const у предопределённой константы.
Использование простое:
И на выходе тип у first и second будет такой:
Песочница: пуньк.
Давайте исходя из полученной информации создадим валидатор по известной схеме данных и дальше поработаем с ним:
Определение getSurname приобретёт такой вид:
То есть, обратите внимание, не просто строку на вход, а конкретные, существующие в нужных параметрах строки.
Теперь это вполне себе напоминает удобную работу с коллекциями данных, не стыдно и форму провалидировать.
Песочница: пуньк.
Штука относительно новая, к ней ещё придётся немного привыкнуть. Но уже можно пробовать применять.
Ах да, ссылка на соответствующий PR в TypeScript: https://github.com/microsoft/TypeScript/pull/51865
#typescript #generic #const
Типом дня назначается вон тот в кожаной куртке. Да-да, о тебе говорю!
TL;DR: вычисленный тип функции с дженерик-аргументом можно сузить, декларируя тип как const.
Кроме шуток, разве тебя не бесит, что указываешь вот дженерик тип аргумента функции, производишь манипуляции над переданным объектом — а в ответ тебе вычисленный базовый тип?
Непонятно? Давай так:
function wrapNames <T>(names:T[]) {
return names.map<{name: T}>(name => ({name}));
}
const [first, second] = wrapNames(['Sergey', 'Alex'])
Какой вычисленный тип получат first и second?
Очевидно, такой:
{
name: string;
}
Но... это же довольно неудобно. А если мы схему валидируем, например? Или форму описываем. Или тесты пишем в конце-концов. Почему при заранее известном константном типе входных данных мы получаем вычисленную строку?
К счастью, начиная с TypeScript 5.0 можно объявлять дженерики как константные типы! Иначе говоря, работать с максимально узкими (narrow) типами. Это, собственно, аналог указания as const у предопределённой константы.
Использование простое:
function wrapNames <const T>(names:T[])
И на выходе тип у first и second будет такой:
{
name: "Sergey" | "Alex";
}
Песочница: пуньк.
Давайте исходя из полученной информации создадим валидатор по известной схеме данных и дальше поработаем с ним:
// initValidator
function parse<const T extends { name: string; surname: string }>(users: T[]) {
return (name: T['name']) => users.find(u => u.name === name)?.surname;
}
// validate
const getSurname = parse([
{
name: 'Joe',
surname: 'Doe',
age: 30,
},
{
name: 'John',
surname: 'Dohn'
}
]);
Определение getSurname приобретёт такой вид:
getSurname: (name: "Joe" | "John") => string | undefined
То есть, обратите внимание, не просто строку на вход, а конкретные, существующие в нужных параметрах строки.
Теперь это вполне себе напоминает удобную работу с коллекциями данных, не стыдно и форму провалидировать.
Песочница: пуньк.
Штука относительно новая, к ней ещё придётся немного привыкнуть. Но уже можно пробовать применять.
Ах да, ссылка на соответствующий PR в TypeScript: https://github.com/microsoft/TypeScript/pull/51865
#typescript #generic #const
GitHub
`const` modifier on type parameters by ahejlsberg · Pull Request #51865 · microsoft/TypeScript
With this PR we implement a new const modifier for type parameters. In a function, method, or constructor invocation, when a literal expression in an argument is contextually typed by a const type ...
👍25❤3