3 паттерна TypeScript, которые я использую в своей повседневной работе

RedDeveloper
21.02.2023 13:22
3 паттерна TypeScript, которые я использую в своей повседневной работе

в качестве фрилансера на Toptal

1. Свойства только для чтения

В TypeScript 2.0 в язык был добавлен модификатор readonly.

Свойства, помеченные readonly, могут быть присвоены только во время инициализации или из конструктора того же класса. Все остальные назначения запрещены.

  • Пример
// type definitions

interface Person { readonly name: string; readonly age: number; };

// or

type Person = { readonly name: string; readonly age: number; };

// Usage:

const person: Person = { name: Mike, age: 23 };

Теперь, поскольку свойства name и age объявлены как readonly, значение любого из них не может быть переназначено во время компиляции:

person.name = "Kate" // not allowed
person.age = 33 // not allowed

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

Также стоит прямо заявить, что модификатор readonly является частью системы типов TypeScript, и что после компиляции кода Typescript в JavaScript модификаторы readonly удаляются из кода. Поэтому не существует защиты от переназначения свойств во время выполнения.

2. Защита типов

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

Защитники типов обычно реализуются в виде функций.

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

TypeScript использует некоторые встроенные операторы JavaScript, такие как typeof, instanceof и оператор in, которые используются для определения того, содержит ли объект свойство.

  • Пример 1 - использование оператора "typeof" для построения защиты типа
const isString = (value: unknown): value is string => typeof value === "string";

// ....

if (isString(value)) {
  console.info(value.toUpperCase());
}

Оператор typeof может определять следующие типы, распознаваемые JavaScript; boolean, string, bigint, symbol, undefined, function, number.

  • Пример 2 - использование оператора "in" для построения защиты типа
interface Vehicle {
  manufacturer: VehicleManufacturer;
  model: VehicleModel;
}

interface Animal {
  name: string;
  species: AnimalSpecies;
}

const getUniqueID = (entity: Vehicle | Animal) => {
  if ("manufacturer" in entity) {
    return entity.manufacturer; 
  }

  if ("species" in entity) {
    return `${entity.name} - ${entity.species}`;
  }

  ...
} 

Оператор in проверяет, обладает ли объект определенным свойством. Он также обычно реализуется как функция и возвращает булеву величину.

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

3. Союзные типы

Тип объединения описывает значение, которое может быть одним из нескольких типов. Мы используем вертикальную полосу (|) для разделения каждого типа, поэтому число | строка | булево - это тип значения, которое может быть числом, строкой или булевым числом.

  • Пример 1 - объединение примитивов
type Status = "active" | "inactive" | "pending";

const setStatus = (status: Status) => {
  // ...
}

setStatus("active");
setStatus("pending");
setStatus("invalid"); // Error: Argument of type '"invalid"' is not assignable to parameter of type 'Status'.
  • Пример 2 - сужение союза

Welcome to DeepL Write!

// type guards

const isString = (value: unknown): value is string => {
  return typeof value === "string";
}

const isNumber = (value: unknown): value is number => {
  return typeof value === "number";
}

// simple union type

type ID = "string" | "number";

const getNameFromID = (id: ID) => {
  if (isString(id)) {
    // logic that deals with id: string
  }

  if (isNumber(id)) {
  // logic that deals with id: number
  }

  // default return, or error handling logic
}

getNameFromID("23");

getNameFromID(45);
    This tool allows you to correct mistakes, rephrase sentences and improve your writing. The green highlight on the right indicates a change.
interface Bird {
  weight: number;
  canFly: boolean;
}

interface Dog {
  age: number;
  canFly: boolean;
}

const canAnimalFly = (animal: Bird | Dog) => animal.canFly;

// even better for readability and scalability purposes 

type Animal = Bird | Dog;

const canAnimalFly = (animal: Animal) => animal.canFly;

Click on a word to see suggestions or rewrite the whole sentence.

Но что, если мы хотим получить доступ к свойству weight для объекта bird: Объект "Птица", или свойство "Возраст" у собаки: Объект Dog?

type Animal = Bird | Dog;

const bird: Animal = bird.age // TS error

Компилятор TypeScript пожаловался бы и выдал ошибку.

Поскольку TS является структурно типизированным языком, он разрешает доступ только к свойствам, определенным в обоих интерфейсах.

Техника защиты типов, которая помогает нам удовлетворить компилятор TS:

interface Bird {
  weight: number;
  canFly: boolean;
}

interface Dog {
  age: number;
  canFly: boolean;
}

type Animal = Bird | Dog;

const getAnimalAge = (animal: Animal) => {
  if ("age" in animal) {
    return animal.age;
  }

  return undefined;
}

const getAnimalWeight = (animal: Animal) => {
  if ("weight" in animal) {
    return animal.weight;
  }

  return undefined;
}

Теперь представьте, что мы добавили больше общих свойств в интерфейс Bird или Dog. Или что если мы удалим некоторые общие свойства из обоих интерфейсов, которые также используются внутри защит типов? Например, canFly.Итак, вот модифицированный пример вышеприведенного кода, использующий метод

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

Например:

interface Bird {
  weight: number;
  canFly: boolean;
  ANIMAL_TYPE: "BIRD";
}

interface Dog {
  age: number;
  canFly: boolean;
  ANIMAL_TYPE: "DOG";
}

type Animal = Bird | Dog;

const getAnimalAge = (animal: Animal) => {
  if (animal.ANIMAL_TYPE === "DOG") {
    return animal.age;
  }

  return undefined;
}

const getAnimalWeight = (animal: Animal) => {
  if (animal.ANIMAL_TYPE === "BIRD") {
    return animal.weight;
  }

  return undefined;
}

свойство нашим JS-объектам (которые не имеют никакой бизнес-ценности). А это увеличивает потребление памяти - но, вероятно, не намного.

Заключение

Спасибо, что дочитали эту статью до конца.

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

.org/docs/handbook/typescript-in-5-minutes.html

2) https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html В будущем я буду публиковать больше подобных материалов, так что следите за новостями :)

Ресурсы:

1) https://www.typescriptlang

Laravel с Turbo JS
Laravel с Turbo JS

29.03.2023 12:59

Turbo - это библиотека JavaScript для упрощения создания быстрых и высокоинтерактивных веб-приложений. Она работает с помощью техники под названием "Turbo Links", которая позволяет перемещаться между страницами сайта без полной перезагрузки страницы.

Типы ввода HTML: Лучшие практики и советы
Типы ввода HTML: Лучшие практики и советы

29.03.2023 12:29

HTML, или HyperText Markup Language , является стандартным языком разметки, используемым для создания веб-страниц. Типы ввода HTML - это различные типы элементов управления формами, которые могут использоваться для сбора информации от пользователей на веб-страницах. Существует множество различных...

Аутсорсинг разработки PHP для индивидуальных веб-решений
Аутсорсинг разработки PHP для индивидуальных веб-решений

29.03.2023 09:49

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

Понимание Python и переход к SQL
Понимание Python и переход к SQL

28.03.2023 13:50

Перед нами лабораторная работа по BloodOath:

Слишком много useState? Давайте useReducer!
Слишком много useState? Давайте useReducer!

28.03.2023 12:46

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

Узнайте, как использовать теги <ul> и <li> для создания неупорядоченных списков в HTML
Узнайте, как использовать теги <ul> и <li> для создания неупорядоченных списков в HTML

28.03.2023 10:02

HTML предоставляет множество тегов для структурирования и организации содержимого веб-страницы. Одним из наиболее часто используемых тегов для отображения списков является тег <ul>. В этом уроке мы рассмотрим, как использовать теги <ul> и <li> для создания неупорядоченных списков на веб-странице.