Саша Черный
Персидские вельможи не взлюбили пророка Даниила: был он любимцем царя Дария и приближен к нему больше всех.
Как осудить пророка? Был он добр, мудр и справедлив, и ни в чем нельзя было его обвинить. Решились они извести его хитростью.
Уговорили царя Дария вельможи-сатрапы издать указ, чтобы никто не смел в течение тридцати дней никому, кроме царя Дария, поклоняться.
Подписал царь указ. А пророк, как всегда, встал вечером у окна, поднял глаза к звездному небу и стал молиться Богу.
Вельможам только этого и надо было. Пришли к царю и сказали: «Вот твой любимец пророк Даниил нарушил указ. Поклонился не тебе, а своему Богу. Осуди его, царь, — мы все свидетельствуем против него».
Не легко было Дарию выдать завистливым вельможам Даниила, тянул-оттягивал, но скрепя сердце должен был своему же указу подчиниться.
И отвели пророка ко львиному рву, втолкнули его к голодным хищным зверям, а к выходу привалили камень, и сам царь тот камень своей печатью опечатал.
Старый лев забил упругим хвостом по бедрам, вскочил и поднял голову. За ним гурьбой потянулись львы и львицы. Львята бросили свои игры и широко открыли изумрудные детские глаза. На камне у входа бесстрашно стоял человек, юный и стройный, и улыбался.
— Не боишься? — проворчал старый лев и мохнатой головой коснулся подножия камня, на котором стоял пророк.
— Нет.
— Ты тот, кого люди называют пророком Даниилом? Я тебя сразу узнал: у тебя бесстрашное сердце и львиная поступь.
— Мы его будем есть? — спросил годовалый львенок у матери, но львица лапой отбросила львенка на песок. — Поди прочь, шакал! Его нельзя трогать… Он не такой, как все. Орел нам вчера сказал, что Даниил на охоте не пронзил копьем ни одного льва.
Всегда мимо бросает… А кто нам со стены рва кидал не раз кости и мясо с царской кухни? Ты не узнал?.. Он добр ко всем, даже к паукам.
Львенок удивленно замурлыкал и, сев на задние лапы, стал рассматривать Даниила: ишь какой, — ничуть не боится…
Даниил легко соскочил с камня — расступились звери — подошел к львенку, склонился и положил ему руку на темя. Впервые пальцы человека коснулись головы львенка, и показалось ему, что не человек пощекотал его за ухом, а язык матери, теплый и ласковый.
— Ну, что же, будешь меня есть? — улыбнулся Даниил.
— Нет, не буду. Ты разве понимаешь нашу речь? — удивился львенок.
— Да. Бог добр ко мне: я понимаю, о чем шумит вода, о чем шепчутся деревья, что говорят, перекликаясь в саду, птицы, и ваш язык — мне знаком.
К Даниилу подобрался, осторожно нюхая воздух, другой львенок, — совсем крохотный, не больше кошки, потерся о его ноги и заурчал.
— Погладь и меня… Он ведь большой, а я маленький.
Рассмеялся Даниил, сел наземь, взял второго львенка на руки, а за ним и другие львята на колени к нему полезли.
Довольные львицы облизнулись: сразу видно, этот умеет с малышами обходиться. А львы разлеглись кругом у скал в тени, прищурили зрачки и, не мигая, стали смотреть. Не каждый день такую штуку увидишь.
— Бороться хотите? — спросил Даниил, встал на ноги, слегка их расставил и уперся руками в сильные бока.
Дремавший орел испуганно встрепенулся на скале: вот визжат. Что это они там затеяли?
А львята пушистой гурьбой набросились на Даниила. Но разве такого повалишь. Лезли, вставали на задние лапы, упирались мордами в упругие колени, но человек ни с места. И вдруг отскочил в сторону — так и повалились зверята на горячий песок… Вот ведь хитрый какой.
Потом бегали вперегонки. У человека две ноги, а у львят по четыре, но куда там. Никто Даниила не обогнал, только угомонились, высунули языки, разлеглись под скалой рядом с Даниилом, бока, как кузнечные меха, ходят.
Львица, мать самого маленького львенка, лапу ему в расщелину камня сунула, вытащила полуобглоданную кость, принесла и перед Даниилом положила: ешь…
Но он только головой покачал и рассмеялся.
Цикады над головой затрещали. Жарко и тихо.
— А ты рычать умеешь? — спросил Даниила маленький львенок.
— Нет.
— Я тоже не умею.
— Вырастешь, научишься… — Даниил задумался и посмотрел зверенку прямо в зрачки. Львенок отвернул глаза. Рассердился, фыркнул и опять упрямо посмотрел в глаза Даниилу. И опять не выдержал взгляда человека.
— Отчего это? — спросил львенок.
— Что «отчего»?
— Матери я смотрю в глаза и даже большим сердитым львам, а тебе не могу.
— Ну, ты еще малыш. Не поймешь… Сиди тихо и не мешай мне думать.
— Что такое «думать»?
Даниил ничего не ответил, прислонился к теплой скале и положил львенку на спинку ладонь: потянулся звереныш, зевнул — всю пасть открыл, — затих и завел свою сонную кошачью музыку. А цикады все громче трещат.
Подошел незаметно вечер. Пала прохлада. Звери по всем углам расшагались, старый лев на луну морду поднял и заревел: очень уж есть захотелось. А Даниил руки за голову закинул и пролежал недвижимо до рассвета, глядя на светлые звезды и поглаживая жавшихся к нему от ночного холода львят.
Царь Дарий всю ночь не спал и к пище не прикоснулся. Жалко ему было юного Даниила, своего советника и любимца. Голодные львы — не шутка, небось и костей от Даниила не осталось… А вдруг жив? Не сохранил ли его Бог, которому он поклонялся?.. Так ведь спокоен был Даниил, когда его вели в львиный ров, и так светел, точно ничего злого себе от хищных зверей не ждал.
Чуть свет, едва первые птицы в кустах встрепенулись, кликнул царь Дарий воинов и пошел торопливо к львиному рву.
Стал у опечатанного камня и тревожно окликнул:
— Жив ли ты, Даниил?
И из-за камня бодро и радостно отозвался знакомый голос:
— Жив! И ты, царь, живи во веки…
Отвалили камень. Вышел невредимый Даниил. Дарий в радости глазам не верит.
А злые, лукавые вельможи сзади столпились, хмурятся и глаза в землю потупили.
Обернулся Дарий — и, как его ни просил Даниил простить их, не послушался и махнул воинам рукой:
— Бросьте их львам!
Саша Черный.Рассказы.Полный список
Недавно я, используя React Native, занимался разработкой мобильного приложения для медитации Atomic Meditation. Эта программа помогает тем, кто ей пользуется, выработать привычку медитировать, ежедневно уделяя этому занятию какое-то время. В ходе работы у меня появились серьёзные причины приступить к изучению TypeScript и начать пользоваться им вместо JavaScript в проектах среднего и крупного размера.
Прежде чем я начну свой рассказ, мне хотелось бы отметить, что вы сможете разобраться в этой статье, даже если никогда не пользовались React Native. Я буду всё подробно объяснять. А если вы делали какие-нибудь проекты на React, то, читая эту статью, можете считать, что React и React Native — это одно и то же.
А теперь расскажу о том, как обычный JavaScript втянул меня в неприятности.
День 1: всё идёт как надо
В React Native есть объект AsyncStorage
, который представляет собой хранилище данных типа ключ/значение с асинхронным доступом к значениям по ключам. Он даёт разработчику очень простой механизм для организации постоянного хранения данных на мобильном устройстве пользователя.
Например, воспользоваться им можно так:
AsyncStorage.setItem("@key", value)
AsyncStorage
позволяет хранить лишь строковые данные. Поэтому для того чтобы поместить в это хранилище число — это число сначала надо конвертировать в строку.
Ниже показано применение React-хука useState
для объявления переменной sessionCount
и для установки её начального значения в 0. Тут же имеется и функция setSessionCount
, которая позволяет менять состояние sessionCount
:
const [sessionCount, setSessionCount] = useState(0)
Предположим, пользователь завершил сеанс медитации (я, напомню, занимался разработкой приложения для медитации). В sessionCount
хранится общее количество сеансов медитации, завершённых пользователем (я буду теперь называть этого пользователя «Anxious Andy» — «беспокойный Энди»). Это значит, что нам надо прибавить 1
к значению, хранящемуся в sessionCount
. Для этого вызывается функция setSessionCount
, в которой и выполняется прибавление 1
к предыдущему значению sessionCount
. А потом количество завершённых медитаций нужно сохранить в AsyncStorage
в виде строки.
Всё это надо сделать в некоей функции, которую я предлагаю назвать saveData
:
// Пользователь завершил сеанс медитации…
const saveData = () => {
setSessionCount(prev => {
const newSessionCount = prev + 1
AsyncStorage.setItem("@my_number", newSessionCount.toString())
return newSessionCount
})
}
Всё идёт хорошо, наш Энди, теперь уже не такой беспокойный, тихо закроет приложение, испытывая прилив хорошего самочувствия.
День 2: затишье перед бурей
Беспокойный Энди получает уведомление, которое напоминает ему о том, что через 5 минут начинается его медитация. Но он не только беспокойный, но ещё и нетерпеливый. Поэтому он тут же идёт к себе в комнату, находит своё рабочее кресло, удобно (но при этом — сохраняя ясное сознание) в него садится и открывает программу.
Теперь, когда программа загружается, данные сессии Энди нужно прочитать из хранилища. В React хук useEffect
позволяет выполнять функцию-коллбэк при монтировании компонента.
В коллбэке мы асинхронно получаем данные из хранилища, а после этого вызываем функцию setSessionCount()
, передавая ей эти данные, то есть — «1»
:
useEffect(() => {
AsyncStorage.getItem("@my_number").then(data => setSessionCount(data))
}, [])
Беспокойный Энди успешно справляется с ещё одной медитацией. Поэтому к sessionCount
надо добавить 1, что позволит сохранить общее число завершённых сеансов медитации.
Новое значение, как и прежде, мы записываем в хранилище:
// Пользователь завершил сеанс медитации…
const saveData = () => {
setSessionCount(prev => {
const newSessionCount = prev + 1
AsyncStorage.setItem("@my_number", newSessionCount.toString())
return newSessionCount
})
}
К настоящему моменту пользователь завершил 2 сеанса медитации.
День 3: буря
Энди, теперь — уже вовсе не беспокойный, достаёт телефон и открывает приложение для того чтобы в третий раз подряд устроить сеанс медитации (и дела у него идут хорошо).
Он хочет узнать о том, как далеко продвинулся в деле выработки полезной привычки. Поэтому он открывает экран статистики. «О, да тут много всего интересного», — приговаривает он. «Отличная программа!».
Но его любовь к этой программе быстро сходит на нет…
Программа сообщает ему о том, что он провёл 11 сеансов медитации. А он-то медитировал всего два раза!
Неправильная статистика по сеансам медитации
Что пошло не так?
В первый день мы записали в sessionCount
начальное значение — число 0
.
Пользователь завершил сеанс медитации — поэтому мы добавили к sessionCount
1
. Затем мы преобразовали то, что получилось, в строку — в «1»
, после чего записали это в асинхронное хранилище (вспомните — оно может хранить только строковые данные).
Во второй день мы загружаем данные из хранилища и записываем в sessionCount
загруженное значение. То есть — «1»
(строку, а не число).
Пользователь завершает сеанс медитации и мы прибавляем к sessionCount
1
. А в JavaScript «1» + 1
равняется «11»
, а не 2
.
Мы забыли преобразовать строковые данные, считанные из хранилища, в число.
А хуже всего тут то, что наша программа при этом не выдала никаких сообщений об ошибках. Эта ошибка какое-то время оставалась незамеченной, а позже довела нас до неприятностей. Поиск источников подобных проблем может оказаться не таким уж и простым делом.
JavaScript позволил нам свободно, не сознавая того, что мы делаем, поменять в ходе выполнения программы тип данных, хранящихся в переменной.
Решить эту и другие подобные проблемы можно с помощью TypeScript.
Что такое TypeScript?
Если вы не знакомы с TypeScript, то знайте, что это, в сущности, то же самое, что и JavaScript, но оснащённое некоторыми полезными возможностями. В частности, переменные не могут менять типы. А если это случится — TypeScript выдаст сообщение об ошибке.
Браузеры не могут выполнять TypeScript-код. Поэтому TypeScript-файлы проекта надо транспилировать в JavaScript. На выходе получится несколько JavaScript-файлов (или один большой «бандл» с JS-кодом проекта).
Использование TypeScript в React Native-проектах
Добавить поддержку TypeScript в существующий React Native-проект очень просто. А именно, надо будет кое-что установить из npm и сделать пару настроек.
Теперь нужно будет лишь переименовать файлы с кодом, например — App.js
в App.tsx
, после чего заработает автоматическая система контроля типов.
После того, как изменено расширение файла, TypeScript разразится гневной тирадой о том, что аргумент типа 'string | null'
нельзя назначить параметру типа 'SetStateAction<number>'
.
TypeScript предупреждает разработчика о том, что с типами данных что-то не так
Это значит, что мне тут, чтобы избавиться от сообщения об ошибке, надо, во-первых, проверить data
на null
, а во-вторых — преобразовать из строки в число (воспользовавшись parseInt()
):
useEffect(() => {
AsyncStorage.getItem("@my_number").then(data => {
if (data) {
setSessionCount(parseInt(data))
}
})
}, [])
Использование TypeScript подталкивает разработчика к написанию более качественного и надёжного кода. Это просто замечательно!
По каким материалам изучать TypeScript?
Я изучал TypeScript по этому видеокурсу канала Net Ninja. И если бы мне надо было бы что-нибудь изучить, то я в первую очередь поинтересовался бы тем, нет ли на этом канале курса по тому, что мне нужно.
Кроме того, официальная документация по TypeScript очень даже хороша.
Итоги
Теперь, благодаря TypeScript, я могу спать немного спокойнее, зная о том, что переменные в моём проекте не могут совершенно неожиданно менять свои типы. Спасибо за это TypeScript.
Да, не могу не отметить, что JavaScript хорошо подходит для маленьких проектов. Но при работе над средними и большими проектами, а так же — над маленькими проектами, которые вполне могут вырасти, лучше, пожалуй, прибегнуть к TypeScript, даже если для этого придётся потратить время на его изучение. А если вы знаете JavaScript, то и TypeScript освоите без особого труда.
Используете ли вы TypeScript в своих React-проектах?