Открыть Электронные книги
Категории
Открыть Аудиокниги
Категории
Открыть Журналы
Категории
Открыть Документы
Категории
Антон Моисеев
2021
ББК 32.988.02-018
УДК 004.738.5
Ф17
Права на издание получены по соглашению с Manning Publications. Все права защищены. Никакая часть
данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения
владельцев авторских прав.
ISBN 978-1617295942 англ. © 2020 by Manning Publications Co. All rights reserved.
ISBN 978-5-4461-1725-3 © Перевод на русский язык ООО Издательство «Питер», 2021
© Издание на русском языке, оформление ООО Издательство
«Питер», 2021
© Серия «Для профессионалов», 2021
Краткое содержание
Введение.................................................................................................................................... 15
Благодарности......................................................................................................................... 17
О книге....................................................................................................................................... 18
ЧАСТЬ 1
ОСНОВЫ СИНТАКСИСА TYPESCRIPT
ЧАСТЬ 2
ИСПОЛЬЗОВАНИЕ TYPESCRIPT В БЛОКЧЕЙН-ПРИЛОЖЕНИИ
Введение.............................................................................................. 15
Благодарности...................................................................................... 17
О книге................................................................................................. 18
Для кого эта книга........................................................................................................... 18
Структура книги.............................................................................................................. 18
О коде................................................................................................................................... 20
Об авторах.......................................................................................................................... 21
Об обложке........................................................................................................................ 22
Часть 1
Основы синтаксиса TypeScript
Часть 2
Использование TypeScript в блокчейн-приложении
Глава 8. Разработка собственного блокчейн-приложения.................................... 214
8.1. Блокчейн 101........................................................................................................... 215
8.1.1. Криптографические хеш-функции...................................................... 217
8.1.2. Из чего состоит блок?............................................................................... 220
8.1.3. Что такое добыча блока?......................................................................... 221
8.1.4. Мини-проект с хешем и nonce............................................................... 224
8.2. Ваш первый блокчейн.......................................................................................... 226
8.2.1. Структура проекта..................................................................................... 227
8.2.2. Создание примитивного блокчейна.................................................... 231
8.2.3. Создание блокчейна с доказательством .
проделанной работы............................................................................................. 234
Итоги.................................................................................................................................. 237
JavaScript прощает очень многое, и это нельзя отнести к недостаткам, если ко-
довая база невелика, а над проектом вы работаете в одиночку. Вероятнее всего,
вы будете помнить, что x должен быть числом, и подсказка тут не потребуется.
Ну и конечно же, если вы будете работать на своего нынешнего работодателя
до конца карьеры, то переменную x вы никогда не забудете.
Этот материал, в свою очередь, предполагает, что у читателей уже есть практи-
ческие познания в HTML, CSS и JavaScript, использующем последние ново-
введения из спецификации ECMAScript. Если вам знаком только синтаксис
ECMAScript 5, рекомендуем просмотреть приложение, чтобы лучше понимать
примеры кода, используемые в книге. Приложение выполняет роль введения
в современный JavaScript.
СТРУКТУРА КНИГИ
Эта книга состоит из двух частей. В части 1 мы рассматриваем различные эле-
менты синтаксиса TypeScript, приводя для наглядности небольшие образцы
кода. В части 2 мы используем TypeScript в нескольких версиях блокчейн-при-
ложения. Если ваша цель — как можно быстрее освоить синтаксис TypeScript
и сопутствующие инструменты, тогда части 1 будет достаточно.
О КОДЕ
Эта книга содержит много примеров исходного кода как в нумерованных ли-
стингах, так и в основном тексте. В обоих случаях исходный код имеет формат
Об авторах 21
ОБ АВТОРАХ
Яков Файн является сооснователем двух IT-компаний: Farata Systems
и SuranceBay. Он автор и соавтор таких книг, как Java Programming: 24-Hour
Trainer, Angular Development with TypeScript1, Java Programming for Kids и др. Яв-
ляясь чемпионом Java, провел множество классов и семинаров, посвященных
веб- и Java-технологиям. Помимо этого, также был докладчиком на междуна-
родных конференциях. Файн опубликовал более тысячи статей в своем блоге
на yakovfain.com. В твиттере и инстаграме его можно найти по адресу @yfain. Он
также публикует видео на YouTube.
1
Файн Я., Моисеев А. Angular и TypeScript. Сайтостроение для профессионалов. — СПб.:
Питер, 2018. — 464 с.: ил.
22 О книге
ОБ ОБЛОЖКЕ
На обложке «TypeScript быстро» изображена «Буржуазная Флоренция». Эта ил-
люстрация позаимствована из коллекции костюмов различных стран, созданной
Жаком Грассе де Сен-Совер (Jacques Grasset de Saint-Sauveur) (1757–1810) под
названием «Costumes civils actuels de tuos les peoples connus», опубликованной
во Франции в 1788 году. Каждая иллюстрация этой коллекции была нарисована
и раскрашена от руки. Богатое разнообразие коллекции Грассе де Сен-Совер
наглядно напоминает нам, насколько культурно разрознены были города и ре-
гионы всего мира еще 200 лет назад. Будучи изолированными друг от друга,
люди говорили на различных диалектах и языках. На сельских же улицах было
достаточно взглянуть на одеяние жителя, чтобы распознать, откуда он родом,
кем работает и в каком жизненном положении находится.
Цель этой главы — помочь вам начать использовать TypeScript для разработки.
Начнем с выражения почтения самому JavaScript, а затем обоснуем, почему вам
стоит программировать именно в TypeScript. В завершение главы скомпилируем
и запустим очень простую программу, чтобы вы могли проследить рабочий процесс
от написания программы в TypeScript до ее компиляции в исполняемый JavaScript
вариант. Если вы уже опытный JS-разработчик, то нужна весомая причина для
перехода на TypeScript, который в любом случае необходимо компилировать
в JavaScript перед развертыванием. Если вы бэкенд-разработчик, планирующий
изучать фронтенд экосистему, то вам также нужна причина для изучения языка,
отличного от JavaScript. Что ж, давайте рассмотрим эти причины.
Вам может стать интересно, зачем все эти сложности с написанием программы
в TypeScript и его последующей компиляцией в JavaScript, если можно изначаль-
но написать эту программу в JavaScript. Чтоб ответить на этот вопрос, взглянем
на TypeScript с высокоуровневой позиции.
TypeScript
ES.Next
ES 3, 5, 6, 7, 8
В JavaScript ситуация обстоит иначе, так как он ничего не знает о типах пере-
менных вашей программы до начала ее выполнения. И даже в запущенной
программе вы можете изменить тип переменной, просто присвоив ей значение
другого типа. В TypeScript же, если вы объявляете переменную как string, то
попытка присвоить ей численное значение приведет к ошибке при компиляции.
let customerId: string;
customerId = 123; // ошибка при компиляции
ПРИМЕЧАНИЕ Есть два вида программных ошибок: те, о которых сообщают вспо-
могательные инструменты в процессе набора кода, и те, о которых сообщают поль-
зователи вашей программы. Программирование в TypeScript существенно снижает
количество ошибок второго типа.
Как вы можете видеть, проект состоит из трех файлов TypeScript: a.ts, b.ts и c.ts.
Эти файлы должны быть скомпилированы в JavaScript компилятором TypeScript
(tsc), который сгенерирует три новых файла: a.js, b.js и c.js. Чуть позже мы по-
кажем, как настроить компилятор на генерацию JavaScript конкретных версий.
На рис. 1.3 изображено всего три файла, но в реальных проектах их число может
достигать сотен и даже тысяч. Разработчики не хотят развертывать такое мно-
жество файлов на веб-сервере или в самостоятельном JavaScript-приложении,
поэтому обычно мы связываем эти файлы (конкатенируем) вместе.
На рис. 1.3 изображена всего одна развернутая связка — main.js. Если бы это
было веб-приложение, то в нем бы был HTML-файл с тегом <script src='main.
js'>. Если бы приложение запускалось в самостоятельном JavaScript-движке
вроде Node.js, то вы могли бы начать со следующей команды (предполагается,
что Node.js установлен):
node main.js
Type JavaScript
definition file library
Iodash.d.ts Iodash.js
Для начала вам потребуется скачать и установить текущую версию Node.js с https://
nodejs.org. Он установит node и npm.
В примерах кода этой книги мы использовали TypeScript 3-й версии или новее.
Чтобы проверить версию вашего tsc, выполните следующую команду в терминале:
tsc -v
Для этого есть решение. Компилятор tsc предлагает десятки опций компиляции,
описанных в документации TypeScript (http://mng.bz/rf14), одной из которых
1.3. Использование компилятора TypeScript 33
В песочнице есть меню Options, где можно выбирать опции компилятора. В част-
ности, можно выбрать целевую версию для компиляции, например ES2018 или
ES5.
Если хотите запускать фрагменты кода из командной строки без участия брау-
зера, установите TypeScript Node REPL, доступный по ссылке https://github.com/
TypeStrong/ts-node.
34 Глава 1. Знакомство с TypeScript
СОВЕТ Опция компилятора target также используется для проверки синтаксиса. На-
пример, если вы укажете целевую версию для компиляции как es3, TypeScript будет
ругаться на методы-геттеры в вашем коде. Так произойдет потому, что он не знает,
как компилировать геттеры в версию ECMAScript 3.
СОВЕТ Для начала нового проекта TypeScript запустите команду tsc --init в любой
директории. Она создаст за вас файл tsconfig.json, содержащий все опции компиля-
тора, большинство из которых будут закомментированы. Раскомментируйте их при
необходимости.
Открыть еще
одно окно
На рис. 1.6 в нижней части черной панели слева вы можете увидеть квадратную
иконку, которая используется для поиска и установки расширений с маркетплей-
са VS Code. Такие расширения могут сделать программирование в TypeScript
более гибким:
38 Глава 1. Знакомство с TypeScript
ИТОГИ
TypeScript — это надмножество JavaScript. Программа, написанная на
TypeScript, должна быть сначала транспилирована в JavaScript, а только
затем может быть выполнена в браузере или отдельном движке JavaScript.
Ошибки перехватываются статическим анализатором кода TypeScript во
время набора еще до компиляции кода компилятором tsc.
TypeScript дает преимущества статически типизированных языков везде, где
это нужно, не препятствуя при этом использованию старых добрых динами-
ческих объектов JavaScript.
TypeScript следует новейшим спецификациям стандарта ECMAScript и до-
бавляет к ним типы, интерфейсы, декораторы, переменные членов классов
(поля), обобщенные типы, перечисления, ключевые слова public, protected,
private и другие возможности. Ознакомьтесь с дорожной картой TypeScript
здесь: https://github.com/Microsoft/TypeScript/wiki/Roadmap, чтобы узнать о текущих
и будущих возможностях.
Чтобы начать новый проект TypeScript, выполните команду tsc --init в лю-
бой директории. Она создаст за вас файл tsconfig.json, который будет содержать
все опции компилятора, большинство из которых будут закомментированы.
Раскомментируйте их по необходимости.
В этой главе:
Базовые
и пользовательские типы
2
33 Объявление переменных с типами и использование типов в объявле-
ниях функций.
33 Объявление псевдонимов типов с помощью ключевого слова type.
33 Объявление пользовательских типов с помощью классов и интерфей-
сов.
Можно рассматривать TypeScript как JavaScript с типами, хотя это будет очень
упрощенное представление, так как в TypeScript имеются элементы синтаксиса,
отсутствующие в JavaScript (например, интерфейсы, обобщенные типы и др.).
Тем не менее основная сила TypeScript заключается именно в типах.
Тип может быть присвоен переменной явно самим разработчиком либо неявно
(вывод типа) компилятором TypeScript. На рис. 2.1 мы объявили переменную
taxCode, не присваивая ей тип. Присваивание значения 1 этой переменной по-
зволяет компилятору понять, что ее тип — number. Это пример вывода типа.
Большинство примеров кода в следующем разделе используют явные типы, за
парой исключений, помеченных как выведенные.
2.1. Объявление переменных с типами 41
};
console.log (myOrder['ord']); Эта строка выводит «123»
42 Глава 2. Базовые и пользовательские типы
СОВЕТ Если тело функции не имеет инструкции return, то она все равно воз
вращает значение undefined . Аннотация типа void может использоваться для
предотвращения случайного возвращения программистами явного значения из
функции.
Следует избегать явных аннотаций типов там, где компилятор TypeScript сможет
вывести их сам. Следующий фрагмент кода объявляет переменные age и yourTax.
В нем нет необходимости указывать типы этих переменных, поскольку компи-
лятор TypeScript и так их выведет.
Мы можем сказать, что переменная name3 имеет литеральный тип John Smith
и допустит только одно значение — John Smith. Любая попытка присвоить другое
значение переменной литерального типа будет обозначена модулем проверки
типов как ошибка:
let name3: 'John Smith';
name3 = 'Mary Lou'; // ошибка: Тип '"Mary Lou"' не может быть присвоен типу
➥ '"John Smith"'
РАСШИРЕНИЕ ТИПОВ
Если вы объявляете переменную, не инициализируя ее с конкретным значением,
TypeScript использует внутренние типы null или undefined, которые преоб-
разуются в any. Это называется расширением типов.
СОВЕТ Добавляйте явные аннотации типов для сигнатур функций или методов,
а также членов публичных классов.
Компилятор это перехватит и выдаст ошибку «Тип ‘number’ не может быть при-
своен типу ‘string’: var tax: string». Такая проверка типов в процессе компиляции
может сэкономить вам уйму времени работы над любым проектом.
Если теперь мы изменим тип padding на объединение string и number (как по-
казано в следующем листинге), то компилятор сообщит об ошибке, если вы
попробуете вызвать padLeft(), предоставив что-либо, кроме string или number.
Это также устранит необходимость выбрасывания исключения.
СОВЕТ Если нужно объявить переменную, которая может содержать значения не-
скольких типов, не используйте тип any; используйте объединение вроде let padding:
string | number. Еще один способ — это объявить две отдельные переменные: let
paddingStr: string; let paddingNum: number.
Давайте изменим код в листинге 2.8, чтобы показать тип never, добавив случай
else к инструкции if. Следующий листинг показывает, как модуль проверки
типов выведет тип never для невозможного значения.
ПРИМЕЧАНИЕ Еще одно преимущество объединенных типов в том, что IDE имеют
функцию автоподстановки, которая предложит допустимые типы аргументов, и вы
уже не сможете сделать в них ошибку.
Сравните код функций padLeft() в листингах 2.6 и 2.9. Каковы основные пре-
имущества использования объединения string | number вместо типа any во
втором аргументе? Если вы используете объединение, компилятор TypeScript
предотвратит некорректные вызовы padLeft(), сообщив об ошибке во время
компиляции.
Здесь { [key: string]: any } означает объект, который может иметь свойства
любого типа, но ключ (key) должен либо иметь тип строки, либо допускать
преобразование в строку.
52 Глава 2. Базовые и пользовательские типы
constructor (
readonly index: number, Значение для этого свойства
readonly previousHash: string, предоставлено конструктором
readonly timestamp: number, во время инстанцирования
Класс Block включает шесть свойств readonly. Обратите внимание, что нам не
нужно явно объявлять свойства класса для аргументов конструктора, которые
имеют квалификаторы readonly, private, protected или public, как мы делали
бы в других объектно-ориентированных языках. В листинге 2.15 два свойства
класса объявлены явно, а четыре неявно.
В правой части рис. 2.4 нет никакого упоминания интерфейса и JavaScript более
лаконичен, что хорошо для любого развертываемого кода. Однако в процессе
разработки компилятор проверит, чтобы объект, предоставленный в качестве
56 Глава 2. Базовые и пользовательские типы
Например, если вы объявите интерфейс Person и при этом у вас будет функция,
получающая аргумент типа Person, то вы не сможете применить к этому аргу-
менту оператор instanceof:
interface Person {
name: string;
}
Модуль проверки типов выдаст ошибку, что Person относится только к типу, но
используется здесь как значение.
Попробуйте еще кое-что: удалите аннотацию типа Person в строке 11. Код по-
прежнему будет рабочим, и в строке 17 не появятся ошибки. Почему TypeScript
позволил вызвать функцию savePerson() с аргументом, которому не был явно
присвоен тип Person? Причина в том, что TypeScript использует структурную
систему типов, а это означает, что если два разных типа включают одинаковые
члены, то эти типы считаются совместимыми. В следующем разделе рассмотрим
структурную систему типов более подробно.
Как можно понять, являются два типа одинаковыми или нет? В Java (использу-
ющем номинальную систему типов) два типа одинаковы, если имеют одинако-
вые имена, объявленные в одном и том же пространстве имен (так называемых
пакетов). В номинальной системе типов, если вы объявляете переменную типа
Person, то можете присвоить ее только объекту типа Person или его потомку.
В Java последняя строка следующего листинга не скомпилируется, так как имена
классов не совпадают, хотя структура у них одинакова.
Customer cust = new Person(); Ошибка синтаксиса: имена классов слева и справа не совпадают
58 Глава 2. Базовые и пользовательские типы
const cust: Customer = new Person(); Никаких ошибок: структуры типов совпадают
class Customer {
name: String;
}
class Customer {
name: String;
}
В листинге 2.20 класс Person имел больше свойств, чем Customer, и код компили-
ровался без ошибок. Скомпилируется ли код следующего листинга, если класс
Customer будет иметь больше свойств, чем Person?
class Customer {
name: string;
age: number;
}
Код в листинге 2.21 не скомпилируется, так как ссылочная переменная cust будет
указывать на объект Person, который даже не выделит память для свойства age,
и присваивание вроде cust.age = 29 окажется невозможным. В этом случае тип
Person уже не может быть присвоен типу Customer.
60 Глава 2. Базовые и пользовательские типы
interface Circle {
kind: "circle"; Дискриминант
radius: number;
}
ЗАЩИТА ТИПА IN
Защита типа in действует как сужающее выражение для типов. Например, если
у вас есть функция, которая может получать аргумент объединенного типа, то
вы можете проверить фактический тип, заданный во время вызова функции.
function foo(x: A | B) {
if ("a" in x) { Проверяет наличие конкретного свойства с помощью in
return x.a;
}
return x.b;
}
Тип unknown был введен в TypeScript 3.0. Если вы объявите переменную типа
unknown, компилятор вынудит сузить ее тип прежде, чем позволит обращаться
к ее свойствам, спасая тем самым от возможных сюрпризов в среде выполнения.
Эта защита типа возвращает true, если передаваемый объект содержит свойство
address. Вы можете применить ее, как показано в следующем листинге.
В этом коде отсутствуют ошибки компиляции, и он будет работать как ожидалось,
пока защита isPerson() не получит в качестве аргумента ложный (вызывающий
false) объект. Например, передача null в isPerson() приведет к ошибке среды
выполнения в выражении "address" в объекте.
2.4. МИНИ-ПРОЕКТ
Если предпочитаете учиться на деле, то предлагаем небольшое задание, сопро-
вождаемое решением. Не будем предоставлять подробное разъяснение этого
решения, так как описание задания должно быть достаточно ясным.
Объявите новый тип Pet в качестве объединения Dog и Fish. Напишите функцию
talkToPet(pet: Pet): string, которая будет использовать защиты типов и либо
вызывать метод sayHello() для экземпляра Dog, либо выводить сообщение «Fish
cannot talk, sorry». (Извините, рыбы не разговаривают.)
Итоги 65
Вызовите talkTopet() трижды, в первый раз передав объект Dog, затем Fish
и в заключение объект, не являющийся ни Dog, ни Fish.
sayHello(): string {
return 'Dog says hello!';
}
}
console.log(talkToPet(myDog));
Вызывает talkToPet(), передавая Pet
console.log(talkToPet(myFish));
talkToPet({ name: 'John' }); Не скомпилируется из-за неверного типа параметра
ИТОГИ
Несмотря на то что объявление типов переменных вынуждает разработчиков
писать больше кода, их продуктивность растет в долгосрочной перспективе.
66 Глава 2. Базовые и пользовательские типы
В этой главе:
33 Принцип работы наследования классов.
3
33 Где и для чего используются абстрактные классы.
33 Как интерфейсы могут принудить класс иметь методы с известными
сигнатурами, не беспокоясь о деталях реализации.
33 Программирование через интерфейсы.
Строка 7 на рис. 3.1 показывает, как вы можете объявить класс Employee, рас-
ширяющий класс Person и объявляющий дополнительное свойство department.
В строке 11 мы создаем экземпляр класса Employee.
3.1. Работа с классами 69
Этот скриншот был сделан после того, как на строке 13 мы ввели empl., после
которой нажали Ctrl-пробел. Статический анализатор TypeScript распознает, что
тип Employee наследован от Person, поэтому он предлагает свойства, определен-
ные в обоих этих классах, Person и Employee.
можете видеть в строке 18, статический анализатор включил этот метод в меню
автоподстановки.
ПРИМЕЧАНИЕ Если вы знаете языки вроде Java или C#, то знакомы с ограниче-
нием уровня доступа посредством ключевых слов private и protected. TypeScript
же является надмножеством JavaScript, который не поддерживает ключевое слово
private, поэтому private, protected (а также public) удаляются при компиляции кода.
Итоговый JavaScript-код не будет содержать их, поэтому вы можете рассматривать
эти ключевые слова просто как помощь при разработке.
Несмотря на то что protected члены класса доступны из кода потомка, они недо-
ступны для экземпляра класса. Например, следующий код не скомпилируется
и выдаст ошибку «Property 'sayHello' is protected and accessible within class
'Person' and its subclasses». (Свойство 'sayHello' является protected и доступно
только внутри класса 'Person' и его подклассов.)
const empl = new Employee(); empl.sayHello(); // ошибка
Сравните рис. 3.4 и 3.5. На рис. 3.4 класс Person явно объявляет три свойства,
которые мы инициализируем в конструкторе. На рис. 3.5 класс Person не имеет
явных объявлений свойств и явных инициализаций в конструкторе.
72 Глава 3. Объектно-ориентированное программирование
Эта версия объявления класса многословна, потому что в ней мы явно объявили
три свойства класса. Конструктор в классе Person выполняет утомительную ра-
боту по присвоению значений из его аргументов к соответствующим свойствам
этого класса.
Теперь давайте объявим более сжатую версию класса Person, как это показано на
рис. 3.5 (или в песочнице http://mng.bz/9w9j). Используя квалификаторы доступа
с аргументами конструктора, мы можем дать команду компилятору TypeScript
создавать свойства класса, имеющие те же имена, что и аргументы конструктора.
Компилятор будет автоматически генерировать JavaScript-код, присваивающий
значения, переданные конструктору, свойствам класса.
Итак, что же лучше — явное или неявное объявление свойств класса? В пользу
обоих этих стилей программирования есть свои доводы. Явное объявление
и инициализация свойств класса могут повысить читаемость кода, в то время
как неявное объявление делает код класса более сжатым. Но вы не обязаны
склоняться именно к одному из этих способов. Например, вы можете объявить
public свойства явно, а private и protected неявно. Мы же чаще всего используем
неявные объявления, если только инициализация свойства не задействует логику.
должно уменьшаться на один. При этом общее число патронов должно быть
известно каждому гангстеру.
shoot(){
Gangsta.totalBullets--; Обновляет количество патронов после каждого выстрела
console.log(`Bullets left: ${Gangsta.totalBullets}`);
}
}
После выполнения кода, приведенного в листинге 3.1 (его можно найти здесь:
http://mng.bz/j5Ya), консоль браузера напечатает следующее:
Bullets left: 99
Bullets left: 98
Теперь давайте рассмотрим другой пример. Представьте, что вам нужно хранить
в памяти важные данные, представляющие текущее состояние приложения.
К этому хранилищу могут обращаться различные сценарии, но вам нужно
обеспечить, чтобы для всего приложения создавался только один такой объект,
который будет единственным источником истины. В таком случае вы прибегаете
3.1. Работа с классами 75
Как же создать класс, который можно инстанцировать всего один раз? Это триви-
альная задача для любого объектно-ориентированного языка программирования,
поддерживающего квалификатор доступа private. Суть в том, что вам нужно
написать класс, который не будет позволять использование ключевого слова
new, потому что с помощью new вы можете создать неограниченное количество
экземпляров. Идея проста: если конструктор класса будет private, то оператор
new работать не будет.
Как же тогда вообще можно создать хотя бы один экземпляр такого класса? Если
конструктор класса является приватным, вы можете обратиться к нему только
внутри класса, и, будучи автором этого класса, вы ответственно создадите его
только один раз, вызвав оператор new из метода этого класса.
appState1.counter++;
Модифицирует counter
appState1.counter++;
(мы используем две ссылочные
appState2.counter++;
переменные)
appState2.counter++;
}
76
const Глава13.=Объектно-ориентированное
appState AppState.getInstance(); программирование
Эта переменная получает ссылку
const appState2 = AppState.getInstance(); на экземпляр AppState
appState1.counter++;
Модифицирует counter
appState1.counter++;
(мы используем две ссылочные
appState2.counter++;
переменные)
appState2.counter++;
}
}
Инстанцирует
const empl = new Employee('Joe', 'Smith', 29, 'Accounting'); подкласс
this.reportToCompliance(symbol, shares);
}
78 Глава 3. Объектно-ориентированное программирование
Обратите внимание, что вы можете написать строку, которая, казалось бы, вы-
зывает абстрактный метод. Но поскольку класс абстрактный, он не может быть
«инстанцирован», и абстрактный (нереализованный) метод никак не сможет
быть выполнен. Если вы захотите создать потомка абстрактного класса, который
может быть инстанцирован, то должны реализовать все абстрактные методы
этого предка.
80 Глава 3. Объектно-ориентированное программирование
Массив workers имеет тип Person, что позволяет нам также хранить в нем эк-
земпляры объектов-потомков.
PROTECTED-КОНСТРУКТОРЫ
В разделе 3.1.3 мы объявили private-конструктор для создания одиночки —
класса, который может быть инстанцирован только один раз. Здесь также есть
применение и для protected-конструкторов. Предположим, вам нужно объявить
класс, который нельзя инстанцировать, но при этом можно инстанцировать его
подклассы. Для этого вы можете объявить protected-конструктор в суперклассе
и вызвать его из конструктора подкласса, используя super().
prodService.getProducts(123);
prodService.getProducts();
Для этого делается объявление всех допустимых сигнатур методов без реали-
зации самих методов, которое сопровождается одним реализованным методом.
prodService.getProducts(123);
prodService.getProducts();
class ProductService {
Первая перегруженная сигнатура
getProducts(description: string): Product[]; getProducts()
getProducts(id: number): Product; Вторая перегруженная сигнатура getProducts()
getProducts(product: number | string): Product[] | Product{
if (typeof product === "number") {
Реализация console.log(`Getting the product info for id ${product}`);
getProducts() return { id: product, description: 'great product' };
} else if (typeof product === "string") {
console.log(`Getting product with description ${product}`);
return [{ id: 123, description: 'blue jeans' }, Смотрит, был ли метод
{ id: 789, description: 'blue jeans' }]; вызван с помощью
} else { description продукта
return { id: -1,
description: 'Error: getProducts() accept only number or
➥ string as args' };
} Смотрит, был ли метод
} вызван с помощью
id продукта
}
console.log(prodService.getProducts(123));
console.log(prodService.getProducts('blue jeans'));
getProducts(123)
возвращает один объект
getProducts('blue jeans')
возвращает массив
На рис. 3.10 показана вторая подсказка (обратите внимание на 2/2) для вызова
метода getProducts() с другим параметром и возвращаемым типом.
class Product {
id: number;
description: string; Конструктор класса
с опциональным аргументом
constructor(properties?: ProductProperties ) { типа ProductProperties
// Constructor implementation goes here
}
}
Предположим, у вас есть Toyota Camry. Она состоит из тысяч деталей, выполня-
ющих различные действия, но как водителю вам требуется знать только набор
управления — как заводить и глушить двигатель, как газовать и тормозить, как
включать радио и т.