Что такое TypeScript?

JavaScript один из самый популярных языков программирования. Одна из причин этого, что он является динамически типизированным. Другим словами, JavaScript – это более свободный язык, но, если вы встретите много кода в вашем проекте, то эта свобода может перерасти в панику.

Давайте взглянем на данный код.

const pikachu = (a, b) => {
  return a + b;
}

Можете ли вы угадать, что вернет этот код?

Я не могу, т.к. функция pikachu может принимать в себя значения любого типа, к примеру, строка, число и т.д.

// Передается число.
const pikachu = (a, b) => {
  return a + b;
}
const result = pikachu(2021, 9);
console.log(result); // 2030
// Передается строка.
const pikachu = (a, b) => {
  return a + b;
}
const result = pikachu("2021", "9");
console.log(result); // 20219

JavaScript это язык с динамической типизацией. Это полезно тем, что позволяет писать код более легко. Но, разработчики должны уделять больше внимания типам аргументов, которые нужны в функции, а также какое значение должно возвращаться. Чем больше и больше вы читаете различный код, тем более это начинает раздражать.

С другой стороны, пожалуйста, посмотрите на данный код.

const pikachu = (a: number, b: number): number => {
  return a + b;
}

Данный код на typescript. TypeScript – это язык с статической типизацией. Когда мы смотрим на это, мы сразу можем понять, что значение, которое возвращает функция pikachu будет числом.

Очень полезно быстро понимать код, потому что при работе вы будете встречаться с большим количеством кода.

Так что, мы должны использовать более легкие в чтении методы, чтобы в дальнейшем, быстрее читать и понимать код, который кто-либо написал в прошлом.

Основы TypeScript

TypeScript имеет несколько примитивный типов данных, таких как string, number, boolean, null, undefined.

Это код с простыми типами данных.

const caterpie01: number = 2021;    // OK
const caterpie02: number = false;   // Не ок

const Metapod01: string = "sleepy"; // OK
const Metapod02: string = true;     // Не ок

const Wartortle01: boolean = true;  // OK
const Wartortle02: boolean = 1111;  // Не ок

При запуске кода мы сразу встречаем несколько ошибок.

typescript.ts:10:7 - error TS2322: Type 'boolean' is not assignable to type 'number'.

10 const caterpie02: number = false;   // Не ок
         ~~~~~~~~~~

typescript.ts:13:7 - error TS2322: Type 'boolean' is not assignable to type 'string'.

13 const Metapod02: string = true;     // Не ок
         ~~~~~~~~~

typescript.ts:16:7 - error TS2322: Type 'number' is not assignable to type 'boolean'.

16 const Wartortle02: boolean = 1111;  // Не ок
         ~~~~~~~~~~~

Дальше, давайте посмотрим на null и undefined.

const Butterfree: null = null;
const ButterfreeNull: string = Butterfree;
console.log(ButterfreeNull) // null

const Kakuna: undefined = undefined;
const KakunaNull: string = Kakuna;
console.log(KakunaNull) //undefined

Этот код работает. Мы можем устанавливать значения null и undefined строкам. В данном случае, я не использовал strict mode. При использовании же, код работает примерно так.

typescript.ts:21:7 - error TS2322: Type 'null' is not assignable to type 'string'.

21 const ButterfreeNull: string = Butterfree;
         ~~~~~~~~~~~~~~

typescript.ts:25:7 - error TS2322: Type 'undefined' is not assignable to type 'string'.

25 const KakunaNull: string = Kakuna;

И это хорошо! Мы сразу можем отлавливать ошибки.

Вы можете установить strict mode в tsconfig.json или использовать аргумент командой строки tsc --strict. Если вы не уверен, в том, как настраивать typescript, вы модете посмотреть примеры на офф. сайте.

Что такое тип данных “any”?

В TypeScript можно использовать тип данных any. Это позволяет работать с любым типом данных без ошибок. Прямо как в обычном javascript.

Давайте взглянем на пример кода.

let pidgey: any = 1991;
console.log(typeof pidgey) // number

pidgey = "bird";
console.log(typeof pidgey) // string

pidgey = false;
console.log(typeof pidgey) // boolean

pidgey = null;
console.log(typeof pidgey) // object

pidgey = undefined;
console.log(typeof pidgey) // undefined

Переменной pidgey можно присвоить любой тип данных!

Это магический тип данных. ????

Если вы собираетесь использовать тип данных any, то TypeScript нам сразу становится не нужным. Просто пишите код на JavaScript.

TypeScript также может сам определять какой тип данных будет использоваться, если мы его не указываем.
Мы можем заменить код из первого примера на данный.

const caterpie01: number = 2021;     // number
const caterpie001 = 2021;            // number  - выбор typescript 


const Metapod01: string = "sleepy";  // string
const Metapod001 = "sleepy";         // string  - выбор typescript 

const Wartortle01: boolean = true;   // boolean
const Wartortle001 = true;           // boolean - выбор typescript 

Это более читаемый и короткий способ записи. И, конечно, мы не сможем присвоить любой другой тип данных в переменную.

let caterpie001 = 2021;            // number
caterpie001 = "text";              // type error

С другой стороны, если мы не укажем тип данных для аргументов функции, typescript выберет тип any. Посмотрим на код.

const pikachu = (a, b) => {
  return a + b;
}
pikachu(2021, 9);

Я получил вот такие ошибки. (В данный момент у меня включен strict mode. Если же его выключить, то код прекрасно отработает)

typescript.ts:57:18 - error TS7006: Parameter 'a' implicitly has an 'any' type.

57 const pikachu = (a, b): number => {
                    ~

typescript.ts:57:21 - error TS7006: Parameter 'b' implicitly has an 'any' type.

57 const pikachu = (a, b): number => {

Всё из-за того, что typescript не может узнать какое значение будет получено.

Для этого тип данных any и был добавлен в typescript. Когда мы используем функции в typescript, мы должны указывать типы данных для аргументов, как на примере.

const pikachu = (a: number, b: number): number => {
  return a + b;
}

Или

// можно также не указывать какой тип данных будет возвращаться
const pikachu = (a: number, b: number) => {
  return a + b;
}

Если вы создаете функцию в typescript, вы обязаны указывать тип данных. Я также рекомендую не использовать тип данных any, за исключением специфичных ситуаций. Таких, как, к примеру, при миграции с JavaScript на TypeScript.

Тип данных для объектов

TypeScript позволяет указывать тип данных для объектов через interface.
Посмотрим на пример.

// Определяем типы данных для объекта
interface PokemonObj {
  name: string,
  age: number,
  skill: string
}
// Назначаем типы
const pokemon: PokemonObj = {
  name: "pikachu",
  age: 6,
  skill: "Electric Shock!"
}

Мы можем использовать interface для создания типа данных для объектов. А затем назначать interface в объекте.
Если мы изменим тип данных внутри объекта, то получим ошибку.

// Определяем типы данных для объекта
interface PokemonObj {
  name: string,
  age: number,
  skill: string
}
// Назначаем типы
const pokemon: PokemonObj = {
  name: "pikachu",
  age: "change age", // изменили
  skill: "Electric Shock!"
}

Ниже текст ошибки.

typescript.ts:75:3 - error TS2322: Type 'string' is not assignable to type 'number'.

75   age: "change age",
     ~~~

  typescript.ts:69:3
    69   age: number,
         ~~~
    The expected type comes from property 'age' which is declared here on type 'PokemonObj'

Мы получаем ошибку типов. Удобно использовать interface как тип данных у объектов. Но, конечно же, мы можем описывать тип данных объекта сразу в коде, прямо как на примере.

const pokemon: {name: string, age: number, skill: string} = {
  name: "pikachu",
  age: 6,
  skill: "Electric Shock!"
}

Тип данных для массивов

Массив с типами данных выглядит вот так.

const pokemon: string[] = ["pikachu", "Raichu", "Charizard"];

Если мы изменим тип данных, то получим ошибку.

const pokemon: string[] = ["pikachu", "Raichu", false];

Текст ошибки.

typescript.ts:80:49 - error TS2322: Type 'boolean' is not assignable to type 'string'.

80 const pokemon: string[] = ["pikachu", "Raichu", false];

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

const pokemon: Array<string> = ["pikachu", "Raichu", "Charizard"];

Следующим типом данных будут generics(дженерики). Это обширный тип данных. После создания дженерик типа, мы можем определить его. Пример кода ниже.

// Определяем тип данных для массива как дженерик
type Pokemon<T> = T[];
// После, мы можем указывать любой тип данных
const pokemon: Pokemon<string> = ["pikachu", "Raichu", "Charizard"];

// Тоже самое, что и код выше
const pokemon: string[] = ["pikachu", "Raichu", "Charizard"];

Мы можем указывать разные типы данных для дженериков.
Это не особо хороший пример кода, но довольно легкий для понимания как дженерики работают.

// Определяем тип данных для массива как дженерик
type Pokemon<T> = T[];
// После создания дженерика, мы можем выбрать любой тип данных
const pokemon01: Pokemon<string> = ["pikachu", "Raichu", "Charizard"];
const pokemon02: Pokemon<number> = [6, 14, 16];
const pokemon03: Pokemon<boolean> = [true, true, false];

Что такое union?

При использовании union, вы можете указывать сразу несколько типов данных. Пожалуйста, посмотрите на пример кода.

let pokemon: (string | number) = "pikachu";  // OK
pokemon = 6; 

Этот код отработает правильно, т.к. переменная pokemon может быть как строкой, так и числом. Но код ниже не верен

let pokemon: (string | number) = "pikachu";
pokemon = 6;
pokemon = false;      // Не ок

Так как переменная pokemon не может принимать в себе тип данных Boolean, то компилятор выдаст ошибку. Если же вы хотите создать массив, в котором будет использоваться несколько разных типов данных, то вы можете также использовать union.
Пример кода.

// массив с использованием union
let pokemon: (string | number)[] = ["pikachu", "Raichu", 6, 14];

Этот код верный. Но, если мы добавим другой тип данных, мы получим ошибку.

typescript.ts:105:65 - error TS2322: Type 'boolean' is not assignable to type 'string | number'.

105 let pokemon: (string | number)[] = ["pikachu", "Raichu", 6, 14, false];

Если вы будете добавлять в массив значения с разными типами, то union ваш выбор.

Что такое tupple?

Tupple – это точный тип данных.
Для начала, давайте взглянем на пример.

let pokemon: [string, number] = ["pikachu", 6];

Этот код сработает отлично. Данный тип данных, tupple, позволяет нам указывать только 2 элемента, строку и число, в определенном порядке.
Сейчас я вам покажу что будет, если указывать данные с ошибками.

typescript.ts:109:36 - error TS2322: Type 'number' is not assignable to type 'string'.

109 let pokemon02: [string, number] = [6, "pikachu"];      // Не ок
                                       ~

typescript.ts:109:39 - error TS2322: Type 'string' is not assignable to type 'number'.

109 let pokemon02: [string, number] = [6, "pikachu"];      // Не ок
                                          ~~~~~~~~~

typescript.ts:110:47 - error TS2322: Type 'string' is not assignable to type 'number'.

110 let pokemon03: [string, number] = ["pikachu", "text"]; // Не ок
                                                  ~~~~~~

typescript.ts:111:5 - error TS2322: Type '[string, number, number]' is not assignable to type '[string, number]'.
  Source has 3 element(s) but target allows only 2.

111 let pokemon04: [string, number] = ["pikachu", 6, 14];  // Не ок

Тип данных Tupple это сама точность. И, в данном случае, это позволяет нам легко понять предназначение массива, и что он вмещает только 2 элемента. Первый, это строка, а второй, это число.

Выводы

В данном посте я описал базовые типы данных TypeScript’а.

Если вы хотите изучать typescript, то вы можете посмотреть на npm пакеты, созданный на typescript, а также будете писать более читаемый и поддерживаемый код.
Если вы работаете в компании, то знаете, как много кода может быть. Так что, вам приходится читать, а также понимать его в больших количествах. TypeScript помогает понимать код!

Спасибо что потратили своё время на прочтение данного поста.

Комментарии (25)


  1. funca
    13.04.2022 20:38
    +7

    А самое главное не перевели:

    Hello, I am a student in Vancouver, Canada and studying web development.

    Понятно зачем это писал hiro9108 и откуда местами неточности. Парень все равно молодец - он учится. Интересно, почему вы посчитали эту статью достаточно полезной, чтобы тратить время на перевод и оставили все ошибки без изменений?


    1. Doberman2029 Автор
      13.04.2022 21:22
      +2

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

      По поводу ошибок, видимо мне не хватило опыта, чтоб их заметить, когда встречаю очевидные ошибки стараюсь отмечать их в тексте как коментарий переводчика. Если у вас есть свободное время, могли бы указать на ошибочные моменты?


  1. trokhymchuk
    13.04.2022 21:02
    +1

    Можете ли вы угадать, что вернет этот код?

    Результат применения оператора + к двум операндам. Язык на то и имеет динамическую типизацию, что вы описываете скорее логику процесса.

    Статья называется "JavaScript vs TypeScript. Почему Вы должны изучить TypeScript?", но тут лишь одно небольшое сравнение, дальше автор объясняет типы в тайпскрипте.

    Теперь к переводу

    JavaScript – это более свободный язык

    если вы встретите много кода в вашем проекте

    Я не могу, т.к. pikachu функция может принимать в себя значения любого типа, к примеру, строка, число и т.д.

    разработчики должны уделять больше внимания типам аргументов, которые нужны в функции, а также как значение должно возвращаться

    У TypeScript есть несколько примитивный типов данных


  1. CrocodileRed
    13.04.2022 22:30
    -1

    В порядке бреда: возможно, способность функции принимать параметры любого типа не слабость, а супер сила, а вы пытаетесь уместить гениальное в узкие рамки общепринятого. Подумайте ))

    Если серьезно, с типизацией жизнь программиста становится сильно проще, но кто не бредит, тот не пьет шампанское :-)


    1. hellamps
      14.04.2022 04:18

      js дает свободу - хочешь обложись подушками, хочешь - ходи по лезвию, а с тайпскриптом скукота, да


  1. kai3341
    13.04.2022 22:55

    Блог PVS-Studio не раз и даже не два показывал силу и эффективность статического анализа кода как средства отлова ошибок на как можно более ранних стадяих. И вроде бы TypeScript тоже претендует на эту нишу. Но как-то не получается

    let data = { a: 1, b: 2, c: 3 };
    data = JSON.stringify(data);
    data = AnythingOther(data);

    И в таком примере TypeScript будет немножечко не доволен


    1. dopusteam
      14.04.2022 00:34
      +2

      Таким кодом даже я, как разработчик, недоволен


      1. Alexufo
        14.04.2022 01:25

        В что бы вы изменили?


        1. aamonster
          14.04.2022 10:31
          +1

          Лично я бы использовал три разных переменных (точнее, три разных константы). С разными именами, отражающими смысл данных.


          1. mayorovp
            14.04.2022 12:06

            С другой стороны, в том же Rust, который куда более строг в плане типов чем TS, разрешено объявлять переменные с одним и тем же именем любое число раз, и каждый раз с новым типом...


            1. aamonster
              14.04.2022 12:20

              Ну, если это разные переменные – почему бы нет (можно же в C-подобных языках определять переменную с тем же именем внутри вложенного блока, в Rust просто пошли дальше), хотя я бы предпочёл так не делать. В данном же случае присваиваем значения разных типов одной переменной, imho так не стОит делать.


              1. mayorovp
                14.04.2022 12:36

                комментарий был удалён


          1. PaulIsh
            14.04.2022 14:05
            +1

            Или просто использовать данные/результаты как аргументы

            const data = AnythingOther(JSON.stringify({ a: 1, b: 2, c: 3 }));  

            Если это не сверх громоздко и не требуется для отладки, то не вижу смысла выделять переменную/константу для хранения промежуточного результата.


            1. kai3341
              16.04.2022 00:24

              Да, отличная идея. Просто чудесный код. И лимит в 80 символов соблюдается, и отлаживать легко, и читается тоже прекрасно.


              1. dopusteam
                16.04.2022 10:38
                +1

                Товарищ сверху написал, что если не требуется для отладки и не громоздко.

                Ну и что Вы тут отлаживать будете? Stringify?


                1. kai3341
                  16.04.2022 14:51
                  -1

                  То есть несериализуемых в JSON объектов не существует, верно?


                  1. dopusteam
                    16.04.2022 16:34

                    Существует. Но не в этом примере. Но Вы не ответили на вопрос


          1. kai3341
            16.04.2022 00:39
            +1

            Лично я бы использовал три разных переменных (точнее, три разных константы). С разными именами, отражающими смысл данных.

            Это сильно лучше, чем предложение снизу запердолить всё в одну строку. Нередко в этом даже есть смысл. Но в функции, которая занимается, например, только сериализацией данных и ничем больше, заводить гору переменных -- это трэш. Если бизнес скажет, что необходима обфускация потока данных, и вы решите JSON преобразовывать ещё в base64 -- вам придётся затронуть не одну строку, но ещё и следующую. А как удобно в целях отладки отключать этапы! Изменения такого неоднородного кода над одной сущностью будут болезненными.


            1. aamonster
              16.04.2022 08:49

              Всё ещё лучше, чем написать let data:any.


              1. kai3341
                16.04.2022 15:00
                -1

                Тайп чекер не спасает от ошибок в реализации бизнес-логики, о которых я рассказал. Удачной отладки!


    1. Alexufo
      14.04.2022 01:25

      у них же не реалтайм анализатор в отличие от ts?


      1. SlavaRa
        14.04.2022 09:25
        +1

        О каком реалмайм анализаторе в TS идёт речь?


        1. Alexufo
          14.04.2022 11:33
          -1

          Подсветка ошибкой при неправильном использовани js. Типа стираешь переменную присваивая ей undefined. Он говорит незя


          1. SlavaRa
            14.04.2022 12:36

            Это компайл тайм, а не рантайм(этого в TS никогда не было)


      1. kai3341
        16.04.2022 00:43

        у них же не реалтайм анализатор в отличие от ts?

        Что TS, что анализатор PVS-Studio позволяют обнаружить ошибки до запуска кода