В предыдущей статье (часть 1) мы разобрались, что такое typescript, как он работает и как использовать его базовую типизацию в переменных и функциях, сегодня мы продолжим более продвинутую типизацию, разберемся, как типизировать массивы и объекты в чистым способом, и мы также изучим новые структуры данных, которые предлагает нам typescript.

Специальные типы

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

  • Any: это тип, который позволяет нам объявить, что переменная может быть равна любому типу данных, например:
let anyVar:any; 
anyVar="Text"; 
anyVar= 1;
anyVar= true;
anyVar= ["a", "b"];
  • Неизвестный: это тип, который позволяет нам объявить, что у нас нет уверенности в данных, которые будут присвоены переменной, чтобы избежать ошибок, которые могут быть вызваны использованием любого, например:
let anyVar:any = 1
anyVar= true
console.log(anyVar + 5) //It will not return an error and this can be problematic.
let unknownVar:unknown = 1
unknownVar= true
console.log(unknownVar + 5) //It will return an error.

Специальные типы для возвращаемых значений в функциях

-Never: это возвращаемое значение позволяет указать, что функция никогда не должна возвращать никаких значений; то есть функция никогда не завершит выполнение. Примером этого может быть:

function showError(message: string):never{
      thow new Error(message)
      console.log(2) // this line is never executed
}

-Void: это возвращаемое значение позволяет указать, что функция не будет возвращать указанное значение; то есть функция завершит выполнение полностью, но никогда не столкнется с оператором возврата. Примером этого может быть:

function printMessage(message: string):void{
      console.log(message)
      //This function does not contain any return
}

Типы объектов

Объекты можно типизировать, просто определив структуру объекта при объявлении типа переменной, например:

const student: {name:string,age:number, mom:string,dad:string} = {name: "Ander",age:21, mom: "Erika",dad: "Walter"}

Псевдонимы типов

Чтобы сделать наш код намного чище, мы могли бы определить структуру объекта перед использованием типа зарезервированного слова следующим образом:

type Student = {
      mom:string,
      dad:string,
      name:string,
      age:number
}
const student:Student = {
      name: "Ander",
      age:21,
     mom: "Erika",
     dad: "Walter"
}

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

const returnGreeting = (person: Student):string =>{
      return `Hello my name is ${person.name} and my parents are ${person.dad} and ${person.mom}`
}

Вложенные типы объектов

Давайте представим, что у нас есть объекты как свойства объектов, типизация будет очень простой, если мы объявим тип каждого свойства перед следующим образом:

type Contact = {
     email:string,
     linkedin:string
}
type Address = {
     house:number,
     street:string,
     city: string,
     zipcode: number
}
//Then we could combine those types to create our desired type
type Worker = {
     name:string,
     contact:Contact,
     address:Address
}

Необязательные свойства в типах объектов

Если бы нам нужно было создать объекты со свойствами, которые могут быть необязательными, мы могли бы сделать это следующим образом:

type Worker = {
      name?:string, //This property will be optional
      contact:Contact,
      address:Address
}

Свойство только для чтения в типе объекта

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

type User = {
      readonly id: string,
      name:string
}

Пересечение типов объектов

Если бы мы хотели соединить два типа, чтобы создать новый, мы могли бы пересечь оба типа с помощью знака; &, следующим образом.

type Parent = {
    mom:string,
    dad:string
}
type Boy = {
    name:string,
    age:number
}
type Student = Boy & Parents

Массивы

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

const name: string[] = ["a", "n", "d", "e", "r"]
name.push(56) // Error
name.push("56") // OK

Второй синтаксис для определения массива выглядит следующим образом:

const arr: Array<string> = ["a", "n", "d", "e", "r"].

Многомерные массивы

Массивы, содержащие другие массивы, могут быть объявлены путем добавления других квадратных скобок следующим образом:

const example: string[][] = [["A", "B", "C"],["A", "B", "C"]]
const example2: string[][][] = 
   [
     [
        ["A", "B"],
        ["B", "C"],
        ["C", "D"]
     ],
     [
        ["A", "B"],
        ["B", "C"],
        ["C", "D"]
     ]
   ]

Здесь массивы, содержащиеся в константном примере, будут иметь строковый тип.

Типы союзов

Типы объединения — это различные типы, которые могут быть разрешены в переменной, массиве, параметре или возвращаемом значении функции, для этого оператор | используется, если, например, мы объявляем; пусть налог:строка | number = ‘40’ мы разрешаем присвоение текста или номера переменной налога. Другими примерами этого могут быть:

let sizes: "M" | "S" | "XL";
function showPrice(price: string | number):void{ 
     console.log(price)
}

Сужение типов с объединением типов

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

function calTax(price: string | number , tax:number):number{
      //Only if the parameter is a string
      if(typeof price === "string"){
         price.replace("$","")
         price = parseFloat(price.replace("$",""))
      }
      return Number(price) * tax
}

Тип объединения с массивами

Если мы объявим переменную как let arr:number | нить[]; это означает, что этой переменной может быть присвоено число или строка, но если мы хотим использовать типы объединения для значений, содержащихся в строке, мы должны заключить типы в скобки, таким образом, let arr:(number|string)[] ; таким образом мы объявляем, что переменной может быть присвоен только массив, содержащиеся значения которого могут быть только числового или текстового типа.

Кортежи

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

Кортеж — это тип данных, который typescript дает нам для очень строгого ввода инициализации массива, и может быть создан следующим образом: let tuple: [string,number], который указывает, что первое значение должно быть строкой, а второе должно быть числом. При работе с кортежами необходимо учитывать следующее: Порядок имеет значение:

let tuple = [string,number];
tuple=[1, "a"]//Wrong
tuple=["a",1]//Good

После инициализации это будет обычный массив, что означает, что вы можете использовать .push(value) для добавления новых значений, и он будет поддерживать деструктурирование массива.

перечисления

Перечисления — это объект, который может иметь только свойства, и каждое свойство будет строкой или числом. Основное преимущество использования перечислений заключается в выполнении проверок, поскольку это упрощает процесс. Перечисления могут быть объявлены следующим образом:

enum MessageStatus{
    PENDING = "a",
    RECEIVED = "b",
    READ = "c"
}

Если мы не объявим значение для всех свойств, каждое свойство будет числом, упорядоченным по возрастанию и начиная с нуля:

enum MessageStatus{
    PENDING //0,
    RECEIVED //1,
    READ //2
}

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

const status = MessageStatus.PENDING
function isRecieved(status:MessageStatus):boolean{
    return status === MessageStatus.RECEIVED
}
console.log(isRecieved(status))

На сегодня все, в следующей части мы посмотрим, как использовать интерфейсы и как работать с домом.

Спасибо за чтение, следуйте за мной, чтобы узнать больше

Ссылки [1]: typescriptlang.org/docs/handbook/2/everyday..