Комментарии 43
А как получить в рантайме список опций литерального перечисления, для тайпгварда, например?
Вообще тайпгварды кто пишет честные для того же обмена с сервером?
Выглядит как-то очень странно написать динамический тайпгвард и вывести из него статический тип. Я обратную задачу имел в виду — по обычному статическому типу сгенерировать динамический тайпгвард.
Увы, штатными средствами обратная задача нерешаема. Если только распарсить исходник, определить типы и на основании них сделать какую-то ручную кодогенерацию. И все это куда более трудозатратно, чем пойти от динамического typeguard'а и статически определить его тип.
В компиляторе-то она решена, вот только в рантайм это не вынесено.
Typescript Non-goals:
5. Add or rely on run-time type information in programs, or emit different code based on the results of the type system. Instead, encourage programming patterns that do not require run-time metadata.
В результате получаем одну из трёх ситуаций:
- на тайп гварды забивают вообще: as рулит.
- на тайп гвады не полностью забивают, но делают их примитивными по сравнению с типом. Типа проверили, что в свойстве строка, но не проверили, что она содержит значения именно перечисленные в литеральном типе.
- на тайпгварды тратится заметнок количество времени
Есть еще https://github.com/gristlabs/ts-interface-builder, если я правильно понял задачу как генерацию валидационных функций из ts-типов
Еще typescript-is очень хорош, за ним будущее (но требуется пропатченный tsc, хотя его подключить не так уж и сложно).
const getArrayLength = (array: any[]) => array.length
В тайпскрипте можно писать лямбды с обобщенными аргументами типов:
const getArrayLength = <T>(array: T[]) => array.length
const getArrayLength = (array: unknown[]): number => array.length
полагаю — это идеальный вариант. Ни any, ни генерики тут не нужны.
Почему вы считаете тип unknown
более предпочтительным, чем генерик? И зачем явно указывать возвращаемый тип для тела функции из одного выражения?
Почему вы считаете тип unknown более предпочтительным, чем генерик?
Затем, что генерик должен нести смысл, т.е. как-либо использоваться. Данный метод никак не использует этот тип, и даже не передаёт его дальше. Т.е. смысла в генерике просто нет.
И зачем явно указывать возвращаемый тип для тела функции из одного выражения?
В данном случае это просто вкусовщина. не более.
А зачем нужен дополнительный тип-параметр, который фактически не используется нигде в функции? Мне тоже кажется, что лучше честно указать top-тип и не привлекать дополнительных сущностей.
По поводу второго вопроса – это может быть просто полезная привычка писать возвращаемый тип для самопроверки, или же привычка начинать написание функции с описания её типа
Это нормально, что решить задачку можно множеством вариантов, unknown подойдет даже лучше :)
any хорош и удобен в распаковках типов. Посмотрим на встроенные утилиты, извлекающие аргументы или возвращаемое значение из функций:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
Еще классные примеры — в статье, которую я уже приводил выше.
Можно ли тут использовать unknown?
Да (с поправкой на …args)
Нужно ли тут использовать unknown?
¯\_(ツ)_/¯
Не совет, но любопытное наблюдение: система типов TS полна по Тьюрингу. Это значит, что можно писать программы, которые будут выполняться на уровне типов во время компиляции. По ссылке есть примеры калькулятора, считающего выражения на типах, и даже небольшого языка c условиями :)
Вообще говоря, обычно дизайнеры языков стараются делать системы типов НЕ полными по Тьюрингу, потому что с полнотой приходит проблема останова: можно написать такие типы, которые заставят компилятор и среду разработки ощутимо подлагивать (см. шаблоны С++). Но тем не менее, выглядит очень впечатляюще.
Интересно еще, что tsc (вернее, его главная либа) — это, по сути, один большой js-файл (больше сотни тысяч строк), очень независимый, в котором все-все. Конечно, он автоматически бандлится из маленьких, но сам факт занятен.
например,arr[0]
приarr: string[]
имеет типstring
и уже никогда не будет типаstring|undefined
И слава богу! Это прекрасный пример сознательного дизайн-решения, когда user expreience поставили впереди формальной логики. Если так сделать, пользоваться массивами станет невыносимо.
Есть риск увязнуть, начиная от ревью с ЧФ, заканчивая best practices, которые казались реально неплохими.
Для крупных и сложных проектов 10 раз подумал бы прежде, чем внедрять именно TS.
Сама статья хороша.
TS ощущается как типизация на честном слове.
Если вы про soundness — то да, типы в TS являются unsound, и тому есть вполне логичное объяснение. Язык проектируется таким образом, чтобы давать существующей экосистеме условные 80% пользы за 20% затрат. Да, это не 100, но это разумный компромисс. Если для вас этого недостаточно — есть много других компилируемых в JS языков c гарантией soundness (Purescript, Elm, ...) — этой проблемы у них нет, но есть другие :)
Для крупных и сложных проектов 10 раз подумал бы прежде, чем внедрять именно TS.
А что бы вы предложили для крупных и сложных проектов?
А что бы вы предложили для крупных и сложных проектов?
Как раз то, что вы предложили выше. Имел опыт с ReasonML и остался доволен результатом, но признаюсь, перестроиться было непросто.
Есть подозрение, что найти достаточное количество разработчиков на ReasonML будет непросто. И как у него дела с поддержкой всяких популярных библиотек-фреймворков? Например Vue, Bootstrap, прости-хоспади-jQuery?
Поддержка любых сторонних библиотек решается через binding и там на первый план выходит BuckleScript, тут нужна практика.
К счастью, биндить слишком часто мне не приходится, хотя это довольно занимательный процесс. Есть и готовые биндинги, но их не так много пока.
За Vue не скажу, но React вполне комфортно использовать reasonml.github.io/reason-react
Вот это-то меня и насторожило. ReasonML выглядит как прикольная технология, на которой можно попробовать сделать какой-то маленький домашний проектик, получить удовольствие от использования нового подхода и т.д., но чтобы крупный и сложный проект на нем писать, особенно если нужно разрабатывать в быстром темпе и с меняющимися требованиями — имхо, пока рано.
Спасибо за статью. Расскажите подробнее про typescript, dto и swagger. Откуда берутся типы, как формируется документация, что, где и чем валидируется и вот все это?
Вы можете настроить генерацию так, чтобы типы для контрактов собирались автоматически и размещались в какой-нибудь специальной директории вашего проекта.
Тогда схема работы может быть такой: изменился контракт на бэкенде -> запустили генератор и обновили ts-типы -> попробовали собрать проект -> обнаружили и поправили ошибки ts.
Если контракты на бекенде меняются нечасто, то же самое можно делать и вручную. Главная идея в том, что отдельный слой типов и интерфейсов отвечает за контракты с бэкендом и меняется только при изменении этих контрактов.
Совет 8: литеральный тип vs enum
Думаю, стоит заметить, что при использовании литеральных типов сильно усложняется рефакторинг, т.к. IDE не может увидеть связь между литералом в типе и строковым значением параметра.
Так же, типы часто приходится экспортировать/импортировать, и если таких типов много или если где-то используется много компонентов, и каждый из них содержит в себе типизированный параметр, то количество импортов может сильно вырасти. Для себя я вывел идею того, что типы, которые будут использоваться вне компонента, но вместе с ним, можно записать в статичные поля и получится что-то подобное:
enum FlexDirection {...};
enum AlignItems {...};
interface StaticFields {
FlexDirection: FlexDirection;
AlignItems: AlignItems;
}
const FlexContainer: React.FC<Props> & StaticFields = () => {...};
FlexContainer.FlexDirection = FlexDirection;
FlexContainer.AlignItems = AlignItems;
<FlexContainer flexDirection={FlexContainer.FlexDirection...}>...</FlexContainer>
Спасибо за статью! А как сгенерировали картинку со статистикой?
Использование TypeScript в проекте изменяет подход к написанию кода. Становится легче изучать код, ...
Довольно спорное утверждение. Вероятно оно истинно в случае если на проекте нет новичков в тс. Потому-что по своему опыту могу сказать что на проектах с тайпскриптом времени на разработку выходит в половину больше чем без. При этом работали опытные джаваскрипт разработчики — не джуниоры, но с нюансом, что из них никто не любил турескрипт.
С реактом проптайпсы позволяют получить необходимую информацию, без избытка в коде.
Говорят что с ростом кодовой базы тайпскрипт начинает помогать разработчику… Но я за год разработки похоже так и не достиг этого количества кодовой базы, и мои коллеги того же мнения).
Да, но при хорошем знании тайпскрипта код действительно легче и изучать, и рефакторить. Проптайпы есть только для реактовых компонент, всё остальное приходится читать по-старинке, держа в уме возможные значения всех переменных. Когда я перешёл на тайпскрипт, внезапно оказалось, что в фокусе внимания надо держать гораздо меньше вещей, потому что всю эту информацию за тебя обрабатывает компилятор. Можно не проверять каждый раз, что в переменной лежит правильное значение – если это не так, то машина подскажет об этом сама.
А время, которое уходит на написание типов, я считаю, окупается с лихвой – хотя бы потому, что написание типов – это то же проектирование частей приложения, только результаты проектирования мы записываем формальным и частично проверяемым автоматическими средствами способом.
С реактом проптайпсы позволяют получить необходимую информацию, без избытка в коде
Очень слабая альтернатива. Особенно для вложенных типов (если вы конечно не делаете глубоких shape-ов). К тому же весьма многословная и очень слабая в инструментарии. Такое удовольствие доставляет потом вычищать все эти prop-types заменяя их на полноценные типы.
TypeScript определённо замедляет процесс разработки нового кода. Особенно если у вас много generic-кода. Там бывает такие ребусы встают, что можно рабочий день тупо на 1 тип потратить, с непривычки.
TypeScript экономит тонну времени при рефакторингге. С ужасом вспоминаю как я жил без него. Для приложений больше 30 тыщ строк просто незаменимый механизм (разве что Flow).
TypeScript имеет очень высокий уровень входа по сравнению с JavaScript. Потому что ему надо всё доказывать. И не срезать углы. А несрезание углов очень нетривиальная задача. В итоге, мне кажется, все кто в итоге оказался им сильно недоволен, по сути просто так и не овладели этими техниками — затипить то что нетипизируется. Там бывает всё очень непросто. И я очень даже понимаю тех, кто не осилил — иногда это как пробивать головой стену. Ошибки чаще всего нечитаемые. Инструментария как их разрулить вроде нет. Уровней вложенности матрёшек может быть 10+. Всякие "and 21 overloads". Но если осилить этот путь, то потом уже к JavaScript назад дороги нет )
Ещё добавлю — если рефакторинг кода + починка\поиск багов не являются очень большим %-ом от всего времени разработки вашего приложения (т.е. вы пишите write-only код), то, пожалуй, TypeScript вам не нужен.
Вот пара идей, как с этим можно справляться:
В команде/компании есть адвокат ts — хорошо разбирается в теме и приходит на помощь. Также есть отдельный канал по ts, в который можно написать с вопросом.
Оцениваем, насколько стоит вкладываться в типизацию конкретного блока.
Например, есть блок легаси кода на js, который написали год назад и с тех пор не меняли. Фича готова, протестирована, заехала в продакшен. Если она и будет меняться, то вероятно с каким-то глобальным рефакторингом. Врядли стоит тратить много сил на разборки с типами, покрыть основные входы-выходы может быть вполне достаточно.
В команде/компании есть адвокат ts — хорошо разбирается в теме и приходит на помощь
Для большинства компаний это очень утопичное допущение. Найти просто хорошего senior фронтенд разработчика — очень сложная задача. А найти ещё и эксперта в области TypeScript — прямо большая удача.
Например, есть блок легаси кода на js, который написали год назад и с тех пор не меняли
Хорошо работает подход — типизировать по верхам при помощи ts-комментариев.
Для большинства компаний это очень утопичное допущение. Найти просто хорошего senior фронтенд разработчика — очень сложная задача. А найти ещё и эксперта в области TypeScript — прямо большая удача.
Я не предлагал искать отдельного эксперта по TS. Под «адвокатом ts» имею ввиду неформальную роль — человека, которому тема интересна и который готов повышать свой уровень, делиться знаниями с окружающими.
Хорошо работает подход — типизировать по верхам при помощи ts-комментариев.
Точно!
12 советов по внедрению TypeScript в React-приложениях