
TypeScript стал одним из необходимых навыков для современного веб разработчика. В 2019 он вошел в ТОП-10 наиболее используемых языков на GitHub, его поддержку полностью добавили в Create react app, и можно найти массу других свидетельств роста его популярности. В то же время такие языки, как Java и C продолжают сдавать позиции.
Когда мы говорим о преимуществах TypeScript, на ум обычно приходит следующий список:
- TypeScript поддерживает статическую типизацию
- TypeScript делает код проще для чтения и понимания
- TypeScript помогает избежать множества болезненных багов, которые обычно совершают разработчики, благодаря проверке типов в коде
- TypeScript поощряет разработчиков следовать лучшим ООП практикам
- Как следствие вышеперечисленного — TypeScript экономит время разработчиков
Интересно, что все пункты этого списка принимаются на веру без критического взгляда. Сегодня я предлагаю Вам рассмотреть эти пункты внимательней и выяснить, действительно ли они настолько полезны для нас.
Поскольку главной задачей TypeScript является уменьшение количества багов, давайте определимся, почему это так важно? Ответ прост: чем меньше багов — тем меньше дорогостоящего времени разработчиков и тестировщиков мы потратим, следовательно — получим стоящий продукт за меньшие деньги и он начнет приносить доход раньше.
Помня об этом, давайте выясним, как TypeScript может помочь нам улучшить нашу продуктивность и эффективность.
Статическая типизация — волшебная таблетка от багов?
Главная фича TypeScript — поддержка статической типизации. Среди разработчиков распространено убеждение, будто динамическая типизация — источник чуть ли не всех проблем JavaScript разработчиков.
Я гадаю, что плохого люди находят в динамической типизации? Почему на другие динамические языки, например, Python и Ruby, не обрушивается такой шквал критики? Могу лишь предполагать, что проблема не столько в динамической типизации, сколько в приведении типов в JavaScript. Действительно, иногда может очень неприятно удивить код типа такого:

Но это проблема скорее плохого знания JavaScript, а не самого языка. Представьте, что у вас есть мощная спортивная машина. Но ваши водительские навыки достаточно посредственные. Вы будете требовать от производителя машины внести изменения, чтобы уменьшить максимальную скорость машины или научитесь продвинутому вождению и станете выдающимся профессионалом? То, что предлагает нам TypeScript — ограничить возможности динамической типизации вместо того, чтобы как следует выучить JavaScript.
Еще один вопрос к противникам динамической типизации — если статическая типизация так хороша, почему мы все еще встечаем баги в коде, написанном на Java и C#? Да, мы можем отловить эти ошибки на этапе компиляции, но, давайте будем честны, этого недостаточно. Мы должны следовать SOLID принципам и другим лучшим практикам, чтобы обеспечить качественный код. И снова — это относится в большей степени к знаниям и квалификации программистов, чем к языку программирования.
Действительно ли легче читается TypeScript код?
Приведу 2 примера Redux Thunk:
const getUsers = async dispatch => {
//...
try {
const users = await APIService.get('/users')
dispatch(successGetUsers(users))
} catch(err) {
dispatch(failedGetUsers(err))
}
}
и тоже самое на TypeScript:
const getUsers = (): ThunkAction<void, {}, {}, AnyAction> =>
async (dispatch: ThunkDispatch<{}, {}, AnyAction>) => {
//...
try {
const users: User[] = await APIService.get('/users')
dispatch(successGetUsers(users))
} catch(err) {
dispatch(failedGetUsers(err))
}
}
Что значат все эти дженерики? Зачем в них 2 пустых объекта? Сколько времени мы должны потратить на чтение документации, чтобы во всем этом разобраться? Хорошо, это еще нормально для Redux Thunk, поскольку это очень популярная middleware для Redux, у них отличная команда поддержки и документаци��. Но что, если нам придется поддерживать код, который не имеет всего этого?
Больше не будет трудноуловимых багов?
В предыдущем примере Вы увидели, как TypeScript делает код более многословным. Как известно, чем больше и сложнее система — тем больше вероятность ошибки. Помимо тех ошибок, которые мы могли допустить в JavaScript коде, мы должны еще следить за тем, чтобы не сделать опечатку в интерфейсах, ошибку в дженериках, и т.д. Справедливости ради стоит заметить, что компилятор поможет быстро найти и исправить такие ошибки, но без TypeScript мы бы вообще с ними не столкнулись.
Следование лучшим практикам ООП
Как мы знаем, мы должны следовать лучшим практикам, если хотим писать качественный, легко масштабируемый и поддерживаемый код. И TypeScript может нам в этом помочь. Звучит отлично, давайте рассмотрим пример из Express:
userRoute.js
router.get('/users', (req, res) => {
//get users from DB
res.json(users)
})
router.post('/users', (req, res) => {
//create user
res.json(userCreated)
})
userRoute.ts
class UserRouter {
public router = express.Router()
public address = '/users'
constructor() {
this.initRoutes()
}
initRoutes() {
this.router.get(this.address, this.getUsers)
this.router.post(this.addressm this.createUser)
}
getUsers(req: express.Request, res: express.Response) {
//get users from DB
res.json(users)
}
createUser(req: express.Request, res: express.Response) {
//create user
res.json(userCreated)
}
}
Первое, что бросается в глаза — опять пишется больше кода. Мы используем классы, чтобы писать в ООП стиле. Нам придется потом создавать экземпляры этих классов. В добавок, мы можем использовать интерфейсы, статические типы и другие конструкции. И чтобы это все не превратилось в полнейший хаос, нам не остается ничего, кроме как использовать best practices. И это то, что называется: «поощрение разработчиков к использованию лучших ООП практик».
Когда разработчики проголосовали за простые, гибкие и динамичные языки, такие как JavaScript и Python, когда парадигма функционального программирования показала свои преимущества и способность решать некоторые задачи более изящно и эффективно (и в JavaScript мы можем использовать оба подхода), TypeScript подталкивает нас к тому, чтобы писать код по-старинке в стиле ООП Java и C#.
Подводя итог, мы увидели, что TypeScript в действительности не экономит наше время, он ни защищает нас от большого количества багов, ни увеличивает нашу производительность. Более того, он требует написания большего количества кода, дополнительной конфиг��рации, type definition файлов, траты времени на чтение дополнительной документации. Новичок скорее напишет, может, не идеальное, но работающее приложение на JavaScript или Ruby, пока мы будем писать отличное TypeScript приложение в соотвествии со всеми принципами. А потом он наймет нас переписывать его стартап, где мы сможем использовать TypeScript, чтобы сделать все правильно.
Забавно видеть, как массивные, многословные и усложненные языки уходят, не выдержав конкуренции с более динамичными и простыми, а затем последние отказываются от всего, что помогло им так быстро развиться, и стремяться стать тяжеловеснее, многословнее и сложнее.
Я вижу это так:
Окей, мы больше не хотим Java, хотим JavaScript. Но нам не нравится JavaScript таким, как он есть, поэтому давайте сделаем его немножечко более похожим на Java. Отлично, теперь у нас есть все, что было в Java, при этом это не Java. Погнали!