g1er / Andrew

0 stars 0 forks source link

Типы данных в TypeScript: примитивные #20

Open IgorKulishov opened 6 years ago

IgorKulishov commented 6 years ago

TypeScript является "строгим" языком в отличии от JavaScript ( в JavaScript переменная может быть любого типа и тип переменной может меняться в зависимости от типа присваеваемых данных, например: let A = 123; A = 'now it is string'; A = [123, 'now it is array'] ).

В typescript мы прописываем тип переменной при определении переменной (в самом начале) и если в коде программы переменной присвоевается другой тип (не тот который мы определели: к примеру мы ожидаем string а присываевается Array of strings (массив строк)), то TypeScript сигнализирует об ошибке на этапе компилирования, таким образом подсказывая программисту о разнице в типе данных на раней стадии что позволяет устранить потенциальный баг.

Кроме того современные редакторы такие как Visual Studio Code , Intellij (от российской компании JetBrains которыя я использую) , Webstorm (так же от JetBrains, самый популярный среди программистов фронтенда, но они все платные - мы его установим позже) позволяют показывать об ошибке еще до компеляции (этот режим подсказок называется intellisense).

В typescript существует две разновидности типа данных: примитивные (или встроенные в TypeScript или даже JavaScript) и созданные нами в программе (custom) типы данных.

В этой главе мы поговорим о встроенных или примитивных дипах данных:

1.1. Boolean: логическое значение true или false, как видешь типа переменной ставится после названия переменной разделенное двоеточием (и пробелом после двоеточия - это не ошибка если не поставить, но некоторые редакторы такие как Webstorm дают подсказку - просят придерживаться формата):

let humanType: boolean = true;

1.2. Number: числовое значение

  let teamSize: number = 5;

1.3. String: строки

  let teamName: string = "Ferrari";

1.4. Array: массивы (обрати внимание так обозначается массив строк):

 let teamDrivers: string[] = ["Sebastian Vetteli", "Kimi Räikkönen"];

Далее рассмотрим уже не примитивные типы, а относящийся более к custom type (созданный программистом): 1.5. Enum создания числовых констант (набора переменных с присвоенными цифровыми значениями), синтакс (заимствован из объектно-ориентаровынных языков). Работа с enum - в два этапа: а) Сначала мы определяем новый enum с названием и значениями констант б) затем создаем переменную и определяем типу переменной название определенного ранее enum Как примере ниже:

// определяем enum Season c набором констант (времен года), при помощи оператора enum
// каждая из констант в enum имеет неявно показанное значение целого числа, которое начинается с нуля для первой константы 
// и каждая последующая константа имеет значение целого числа увеличенного на +1 от предыдущего значения константы:
// см ниже пример:
enum Season { Winter, Spring, Summer, Autumn };
// создаем переменную и определим тип переменной как enum Season (т.е. currentSeason определен как тип enum Season
// и может значение переменной может быть одним из определенных в  enum Season констант
let currentSeason: Season = Season.Summer;
console.log(current);
current = Season.Autumn; // изменение значения
console.log(current);

Поменять значения констант данных по умолчанию можно след образом:

enum Season { Winter=1, Spring=2, Summer=3, Autumn=4 };

1.6. any: произвольный тип (когда мы не знаем заранее все варианты, иногда на начальной стадии программирования можно вернуть произвольный стиль присвоив переменной тип any, для того что бы компелятор не выдавал ошибку, это будет больше похоже на JavaScript программирование):

let myRandoDataType: any = 123;
myRandoDataType = "let me assign anything";

Ссылка на хорошее объяснение : https://metanit.com/web/typescript/2.5.php Часть из того что приведено в ссылке (к примеру тип данных void), мы рассмотрим этот тип в следующей главе. Мы покрыли только часть того что по ссылке (я умышленно не показал все что бы отдельно посвятить custom типам главу).

Поработай с выше указанными примерами (особенно постарайся поработать с enum, посколькло это новое для тебя). Закомить изменения и напиши вопросы. Удачи!

g1er commented 6 years ago

Насчет определения переменных, точнее его синтаксиса. Это обязательно, что при объявлении новой переменной я должен указывать ее тип, или это опционально, в каких-то особых случаях? С enum в принципе все ясно, примерно такой же принцип, как и с классами: сначала определяем его, задаем параметры, потом используем с параметрами. Только вот проверить на деле не совсем получается. Видать проблемы у меня с компиляцией, или еще с чем. Если помнишь, в самый первый раз я писал, что запуская index.html c подключенным к нему файлом app.js, дебаггер ругался на эту конструкцию:

function greeter(person) {
    return "Hello, " + person;
}
let user = "Jane User";
document.body.innerHTML = greeter(user);

причем ругается не на js-файл, а на ts-файл. И в консоли пишет "Cannot set property 'innerHTML' of null". Чтобы пройти дальше, мне приходится комментить (через //) эту часть кода, причем в js-файле. Дальше дебагер ругается на совмещение 2х ts-файлов в один, когда мы через <refer /> задавали путь, где объявляем класс. В консоли он выдает "Products is not a constructor", видимо не понимая данной конструкции. Более того, при компиляции сам редактор выдает ошибку, что класс используется раньше, чем объявляется:

> Executing task in folder typescript: tsc -p ts <

ts/app.ts(22,19): error TS2449: Class 'Products' used before its declaration.
Процесс терминала завершен с кодом выхода: 2

Теперь же дебагер снова ругается по сегодняшней теме, опять на ts-файл, не распознавая enum, и пишет, что Cars is not defined. Мне не понятно, почему к index.html подключен js-файл, а ругается он на ts-файл. И при этом отказывается выполнять js-код, который вполне приемлемый и к которому у дебагера нет претензий. Все файлы лежат на git, посмотри у себя. Может я что-то неправильно написал или в технических настройках json файла не то задал. Не понимаю в общем. Из-за этого я не могу практическую часть уроков проверять, потому что браузер не хочет выполнять js-код из-за непонятных ему конструкций в ts-файле.

IgorKulishov commented 6 years ago

1)

Насчет определения переменных, точнее его синтаксиса. Это обязательно, что при объявлении новой переменной я должен указывать ее тип, или это опционально, в каких-то особых случаях?

Нет, на самом деле можно не определят тип переменной и ошибки не возникнет. При этом тип определиться после того как переменной будет присвоено первое значение. Например, если присвоить переменной значение строчки, то тип переменной определиться как String, при этом, если попытаться после этого присвоитть этой же переменной значение другого типа, к примеру = 123 (number) - это вызовет ошибку не соответствие типа.

Для того что бы поиграться есть online "песочница" на официальном сайте typescript: https://www.typescriptlang.org/play/index.html Там же в песочнице можно будет попробовать определить переменную без типа и после этого сначала присвоить значение переменной и после попробовать присвоить значение другого типа.

IgorKulishov commented 6 years ago
  1. С enum в принципе все ясно, примерно такой же принцип, как и с классами: сначала определяем его, задаем параметры, потом используем с параметрами.

Не совсем понял сравнение с классом. Класс это ф-ция, а enum это разновидность переменной - точнее набор констрант (набор нескольких констант, значение которых фиксированы и не меняются). В программе мы сначала определяем набор констант с именно цифренными и только цифровыми значениями и когда применяем названия констант в коде программа присваивает им цифренные значения. Как я привел пример выше с временами кода.

// определяем enum Season c набором констант (времен года), при помощи оператора enum
enum Season { Winter=1, Spring=2, Summer=3, Autumn=4 };
// создаем переменную и определим тип переменной как enum Season (т.е. currentSeason определен как тип enum Season
// присваиваем переменной значение из набора enum т.к. может значение переменной может быть одним из определенных в  enum Season констант
let currentSeason: Season = Season.Summer;
console.log(current);
current = Season.Autumn; // изменение значения
console.log(current);

Подводя итог скажу что enum надо применять когда мы хотим присваивать переменной только определенные значения из списка и как бы защититься от случайных вариантов. Наверное это хорошо сделать когда мы хотим ограничиться определенными опциями, к примеру: а) для выпадающего интерфейса списка пола человека или времен года б) или если применять внутри класса - не для пользовательского интерфейса в html, а только константы внутри класса или набор url для обращения к удаленному серверу (хотя обычно это не делают с url). Я приведу еще один пример с enum.

IgorKulishov commented 6 years ago

3. Я вернусь к твоему вопросы насчет enum и покажу пример. Пока разберем твои вопросы из упражений. Желательно конечно вопросы группировать по темам и пунктам.

Итак первый вопрос из упражнений:

И в консоли пишет "Cannot set property 'innerHTML'

Мы уже разбирали пример https://github.com/g1er/Andrew/issues/18 и там надо было поставить условие для проверки наличия document.body на момент первой загрузки и выполнения кода в браузере:

if(document.body) {
    document.body.innerHTML = greeter(user);
}

При этом то что находится внутри setTimeout

setTimeout(function(){
    document.body.innerHTML = greeter(user);
}, 1000);

"document.body.innerHTML" не обязательно окружать условием if(document.body) т.к. таймаут дает небольшую задержку и любой задержки достаточно что бы главный объект html страницы document.body загрузился в браузер - даже если мы поставим 1 миллисекунду или даже 0 миллисекунд (иногда это такой трюк на самом поставить 0 или 1 миллисекунд - и это уже дает на эффект задержки. Такой трюк используется еще когда надо добиться очередости выполнения ф-ций типа одна после другой, при этом это не является хорошим кодом, однако иногда нет вариантов и приходиться прибегать к трюкам пока не найдешь лучшего решения и потом вернуться и поменять).

IgorKulishov commented 6 years ago
  1. Опять таки я вернусь к теме enum позже. Пока разберем твои вопросы / ошибки из упражений.

Дальше дебагер ругается на совмещение 2х ts-файлов в один, когда мы через задавали путь, где объявляем класс. В консоли он выдает "Products is not a constructor", видимо не понимая данной конструкции.

Необходимо по синтаксису поставить

///<reference path="product-class.ts" />

в самом начале (верху) файла (на первую строчку).

IgorKulishov commented 6 years ago
  1. Теперь все должно работать включая твой enum пример (я добавил еще пару строк):

    enum Cars {Jaguar, Audi, Wolksvagen, Lada, Mini};
    let carType: Cars = Cars.Wolksvagen;
    console.log(carType);
    carType = Cars.Lada;
    console.log(carType);

Напиши если есть вопросы или система не работает. Я почищю файлы и распределю их по файлам.

IgorKulishov commented 6 years ago
  1. я содержимое файла app.ts в несколько ts файлов, а сам файл app.ts убрал что бы не путаться с названием app.js значение которого основной файл приложения (app) в котором откомпелировны при помощи при помощи компелятора все составные файла: https://github.com/g1er/Andrew/tree/master/typescript/ts

В файле конфигурации tsconfig.json https://github.com/g1er/Andrew/blob/master/typescript/ts/tsconfig.json , который находится там же где и все исходные файлы ts мы определили что все составные файлы ts будут откомпелированы в один файл app.js https://github.com/g1er/Andrew/blob/master/typescript/js/app.js

Нахождение tsconfig.json определено в другом конфигурационном файле https://github.com/g1er/Andrew/blob/master/typescript/.vscode/tasks.json, указывается в параметре на папку ts: "args": ["-p", "ts"].

Альтернативным вариантом было бы указать в конфигурационном файле на выходе название фолдера а не файла, тогда все файлы бы откомпелировались в отдельные файлы js (greeter.ts -> greeter.js и т.д.).

Не стесняйся задавать вопросы, мы по несколько раз будем проходить по тем же темам. Это новая тема и требуется время освоить. Единственная просьба классифицировать и нумеровать вопросы что бы отслежтвать ответы.

IgorKulishov commented 6 years ago

Пропустил вопрос

Мне не понятно, почему к index.html подключен js-файл, а ругается он на ts-файл. И при этом отказывается выполнять js-код, который вполне приемлемый и к которому у дебагера нет претензий.

Это происходит за счет того что у нас внутри "js" папки есть app.js.map файл (или как их называют map файл) который позволяет строить "карту" между исходными ts файлами и и app.js файлом в браузере. Основная задача map файлов помочь с дебагерами указать девелоперу ошибку и номер строки исходного ts файла. Эти файлы используют во время построения и отладки приложения и удаляются из готового кода, который уже размещают на сайте для клиентов что бы увеличить скорость загрузку (не грузить не нужный код).

Кстати можешь удалить вручную map файл из папки js и ты не сможешь больше дебагить ts в браузере. Можешь попробовать - после того как удалишь перегрузи страницу и перейди в дебагере в закладку Source и нажми Ctrl+O и начинай печатать название любого ts файла - ты их не увидешь. При этом ты сможешь открыть и дебагить (от присутствует и влюбом случае) конечный файл app.js. Что бы не герерировать map файл, так же можно поменять параметр "sourceMap": true в соответственно в "sourceMap": false в конф-ционном файле https://github.com/g1er/Andrew/blob/master/typescript/.vscode/tasks.json

g1er commented 6 years ago

1) Т.е. мне необязательно определять тип перед объявлением каждой новой переменной? это хорошо.

2) не, я не сравнивал функционал классов и enum. я имел в виду схожесть в синтаксисе: сначала объявляем, в классе задаем свойства, в enum константы, а потом используем. просто сравнение в написании.

3) насчет innerHTML я разобрался. я оказывается сам там допустил ошибку. когда ты приводишь примеры, я их не тупо переписываю или копирую в консоль. я читаю, вникаю, запоминаю, а потом сам стараюсь написать код, чтобы вырабатывалась память и чтобы я понимал логику того, что я пишу. в том примере я допустил невнимательность, что в итоге привело к ошибке.

4) та же причина. я думал, что <reference> надо ставить перед кодом, в любом месте. я не понял, что его надо ставить в самом начале, наверху.

5) да, все работает. я, если честно, пока не полностью въехал в enum, в том плане, что это, как и где применяется. я еще почитаю про него, перечитаю твои объяснения. вопрос насчет того, что ты упорядочил ts файлы отдельно. скорее это вопрос по git. я сейчас читал твои ответы и исправлял в файлах, чтобы проверить. только потом дошел до того, что ты разделил файлы. в итоге, когда я хотел залить себе обновление с удаленной директории на git-e, он мне пишет fatal: refusing to merge unrelated histories. не выполняет pull, merge. когда пишу clone он отвечает

$ git clone https://github.com/g1er/Andrew
fatal: destination path 'Andrew' already exists and is not an empty directory 

я понимаю, что это из-за того, что я уже внес изменения в свои файлы, но изменения в них я уже не могу обратить. как быть в таких ситуациях? как залить свежее обновление с гита после того, как уже изменил свои файлы?

6) насчет последнего ответа о том, что app.js.map помогает при дебагинге и связывает исходный ts файл с конечным js. ты вроде говорил, что браузер не понимает typescript. как же он тогда указывает нам на ошибки в исходном ts файле..?

IgorKulishov commented 6 years ago

5. Что произошло - были изменения в удаленном и местном репозитории в одних и тех же файлах. Необходимо разрешить конфликты.

Для того что бы разрешить конфликт локального и удаленного бренчей (если были изменения в удаленном и местном репозитории в одних и тех же файлах), а так же после этого произвести merge (как правило лучше через запрос на merge) необходимо сделать сделать то что описано в уроке 22 https://github.com/g1er/Andrew/issues/22.

Для детального ответа на данный вопрос я создал отдельный урок предлагаю сразу перейти на него для получения ответа по п. 5: https://github.com/g1er/Andrew/issues/22

IgorKulishov commented 6 years ago
  1. Файлы map загружаются в браузер вместе с js файлами и при дебагинге восоздают typescript синтаксис позволяя ставить breakpoints и показывают исходный код в формате ts в браузере. Еще раз перезадай вопрос, если я не смог правильно ответить. Я попробую полностью раскрыть механизм.