Рубрики
Без рубрики

Типы Teamescripts объяснены – умственная модель, которая поможет вам подумать о типах

Однажды я столкнулся с этим Tweet от Lari Mazza: в качестве инженера-программного обеспечения, который сначала узнал Python, Ruby, JavaScript и Clojure, когда я попробовал C ++, это был фильм ужасов. Я не мог сделать много, и это было так контрпродуктивно и разочаровывает. Может потому что я делал все неправильно и

Автор оригинала: FreeCodeCamp Community Member.

Однажды я наткнулся на это Tweet От Лари Мацца:

В качестве инженера программного обеспечения, который изучил Python, Ruby, JavaScript и Clojure, когда я попробовал C ++, это был фильм ужасов. Я не мог сделать много, и это было так контрпродуктивно и разочаровывает. Может быть, потому что я делал все неправильно, и я не понял типов правильно.

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

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

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

Думать в типах JavaScript

Если вы здесь, вы, наверное, слышали, что Tymdercript – это SuperSet javaScript. Если нет, отлично, вы просто узнали что-то новое сегодня. УРА!

Tymdercript – это суперсета, потому что любой код JavaScript действителен в Tymdercript, синтаксически говоря. Это может не скомпилировать в зависимости от конфигурации Compiler TypeyScript. Но с точки зрения синтаксиса он работает просто отлично.

Вот почему вы можете постепенно перенести JavaScript на Teamscript, просто заменяя .js Расширение с .ts Отказ Все будет без типовых деклараций (The любой тип), но это другая история.

Кроме того, если вы код в JavaScript – или любой другой язык программирования – вы, вероятно, думаете о видах:

  • «HM, это список целых чисел, поэтому мне нужно фильтровать только четные номера и вернуть новый список»
  • «Это объект, но мне просто нужно получить это строковое значение от свойства X»
  • «Эта функция получает два параметра. Оба A и B являются целыми числами, и я хочу суммировать их»

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

Чтобы дать более конкретный пример, представьте, что вы хотите суммировать цену всех продуктов. Объект продукта выглядит так:

const product = {
  title: 'Some product',
  price: 100.00,
};

Но теперь со списком продуктов:

const products = [
  {
    title: 'Product 1',
    price: 100.00,
  },
  {
    title: 'Product 2',
    price: 25.00,
  },
  {
    title: 'Product 3',
    price: 300.00,
  }
];

ОК! Теперь мы хотим функцию, чтобы суммировать все цены на продукцию.

function sumAllPrices(products) {
  return products.reduce((sum, product) => sum + product.price, 0);
};

sumAllPrices(products); // 425

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

Первая часть: продукты в качестве аргумента. Здесь вы просто думаете: «Ну, мы получаем список некоторых объектов». Да, в наших головах продукты являются списком. Вот почему мы можем думать об использовании Уменьшить метод. Это метод от Массив опытный образец.

Тогда мы можем подробно подумать об объекте. Мы знаем, что объект продукта имеет Цена имущество. И это свойство – это число. Вот почему мы можем сделать Product.price и сумма с аккумулятором.

Отключение:

  • Продукты это список объектов.
  • В качестве списка мы можем использовать Уменьшить Метод, как этот метод является членом Массив опытный образец.
  • производить Объект имеет некоторые свойства. Один из них – Цена это число.
  • В качестве свойства номера мы можем использовать его для суммы с помощью сокращения аккумулятора.
  • Мы хотели вернуть номер, сумма всех цен на товары.

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

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

STRPERS Типы и простое использование

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

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

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

Как и в JavaScript, TypectScript также имеет основные типы данных, такие как Номер , строка , логический , null и т. Д. Вы можете найти все основные типы данных в Teamescript Docs Отказ

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

Как это работает в JavaScript?

function sum(a, b) {
  return a + b;
}

Все в порядке? Хорошо.

Теперь давайте будем использовать это:

sum(1, 2); // 3
sum(2, 2); // 4
sum(0, 'string'); // '0string'   WTF!

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

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

Что мы хотим? Мы хотим добавить некоторые ограничения на функцию. Это будет возможность получать только цифры. Таким образом, мы сужаем возможность неожиданного поведения. И тип возврата функции также является числом.

function sum(a: number, b: number): number {
  return a + b;
}

Большой! Это было очень просто. Давайте позвоним снова.

sum(1, 2); // 3
sum(2, 2); // 4
sum(0, 'string'); // Argument of type '"string"' is not assignable to parameter of type 'number'.

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

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

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

const isTypescript: boolean = true;
const age: number = 24;
const username: string = 'tk';

Теперь давайте увеличиваем вызов. Помните объектный код продукта, который мы написали в JavaScript? Давайте реализуем его снова, но теперь с помощью SpeckStry Mindset.

Просто чтобы помнить, о чем мы говорим:

const product = {
  title: 'Some product',
  price: 100.00,
};

Это значение продукта. У этого есть Название как строка и Цена как Номер Отказ На данный момент это то, что нам нужно знать.

Тип объекта был бы чем-то вроде этого:

{ title: string, price: number }

И мы используем этот тип для аннотации нашей функции:

const product: { title: string, price: number } = {
  title: 'Some product',
  price: 100.00,
};

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

const wrongProduct: { title: string, price: number } = {
  title: 100.00, // Type 'number' is not assignable to type 'string'.
  price: 'Some product', // Type 'string' is not assignable to type 'number'.
};

Здесь он ломается на два разных свойства:

  • Название это строка и не должен получать Номер Отказ
  • Цена это Номер и не должен получать строка Отказ

Компилятор помогает нам ловить такие ошибки типа.

Мы могли бы улучшить аннотацию этого типа, используя концепцию под названием Тип псевдонимов Отказ Это способ создать новое имя для определенного типа.

В нашем случае тип продукта может быть:

type Product = {
  title: string;
  price: number;
};

const product: Product = {
  title: 'Some product',
  price: 100.00,
};

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

Теперь, когда у нас есть этот тип продукта, мы можем использовать его для ввода списка продуктов. Синтаксис выглядит так: MyType [] Отказ В нашем случае Продукт [] Отказ

const products: Product[] = [
  {
    title: 'Product 1',
    price: 100.00,
  },
  {
    title: 'Product 2',
    price: 25.00,
  },
  {
    title: 'Product 3',
    price: 300.00,
  }
];

Теперь функция Sumallprics Отказ Он получит продукт и вернет номер, сумма всех цен на продукцию.

function sumAllPrices(products: Product[]): number {
  return products.reduce((sum, product) => sum + product.price, 0);
};

Это очень интересно. Как мы набрали продукт, когда мы пишем продукт. , он покажет возможные свойства, которые мы можем использовать. В корпусе типа продукта он покажет свойства Цена и Название Отказ

sumAllPrices(products); // 425
sumAllPrices([]); // 0
sumAllPrices([{ title: 'Test', willFail: true }]); // Type '{ title: string; willFail: true; }' is not assignable to type 'Product'.

Передача Продукты приведет к стоимости 425 Отказ Пустой список приведет к значению 0 Отказ И если мы пройдем объект с другой структурой – Tymdercript имеет систему структурных типов, и мы рассмотрим глубоко в эту тему позже – компилятор бросит ошибку типа, рассказывая о том, что структура не является частью Продукт тип.

Структурная печатание

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

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

class Person {
  String name;
}

class Client {
  String name;
}

Client c = new Person();  // compiler throws an error
Client c = new Client();  // OK!

В системах номинальных типов соответствующая часть типа – это имя, а не структура.

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

Тот же код реализации, который вылетает в Java, будет работать в Teadercript.

class Person {
  name: string;
}

class Client {
  name: string;
}

const c1: Client = new Person(); // OK!
const c2: Client = new Client(); // OK!

Мы хотим использовать Клиент Тип, и у него есть свойство Имя , чтобы указать на Человек тип. Он также имеет тип свойства. Таким образом, TypeScript поймет, что оба типа имеют одинаковую форму.

Но это не только о классах, но это работает для любого другого «объекта».

const c3: Client = {
  name: 'TK'
};

Этот код также компилирует, потому что у нас здесь такая же структура. Система TypeScript Type не заботится о том, если это класс или литерал объекта, если у него есть те же участники, он будет гибким и компитенным.

Но теперь мы добавим третий тип: Клиент Отказ

class Customer {
  name: string;
  age: number;
};

У него не только Имя Собственность, но и возраст Отказ Что произойдет, если мы создали экомацию Клиент экземпляр в постоянной типа Клиент ?

const c4: Customer = new Client();

Компилятор не примет этого. Мы хотим использовать Клиент , что имеет Имя и возраст Отказ Но мы создаем создание Клиент у этого есть только Имя имущество. Так что у него нет такой же формы. Это приведет к ошибке:

Property 'age' is missing in type 'Client' but required in type 'Customer'.

Наоборот, наоборот будет работать, потому что мы хотим Клиент и Клиент Есть все свойства ( имя ) от Клиент Отказ

const c5: Client = new Customer();

Работает нормально!

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

Время выполнения и время компиляции

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

В основном, время выполнения – это время выполнения программы. Представьте себе, что ваши данные получают данные с страницы формы Frontend, обрабатывая эти данные и сохраняя ее. Или когда ваш интерфейс запрашивает данные с сервера, чтобы сделать список Покемоны продукты.

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

Например, например, очень связаны с кодом, который мы написали раньше:

  • Когда тип отсутствует свойство: Свойство «Возраст» отсутствует в типе «клиент», но требуется в типе «Клиент».
  • Когда тип не совпадает: Тип '{Название: строка; Willfail: правда; } 'не является назначенным на тип «продукта».

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

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

function getIndexOf(language, part) {
  return language.indexOf(part);
}

Это получает Язык и Часть Что мы будем искать, чтобы получить индекс.

getIndexOf('Typescript', 'script'); // 4
getIndexOf(42, 'script'); // Uncaught TypeError: language.indexOf is not a function at getIndexOf

При прохождении строки он работает нормально. Но пропуская номер, мы получили ошибку выполнения Неуправляемая типография Отказ Потому что номер не имеет Индекс Функция, поэтому мы не можем его использовать.

Но если мы дадим информацию о типе компилятору в компиляторе, он бросит ошибку перед запуском кода.

function getIndexOf(language: string, part: string): number {
  return language.indexOf(part);
}

Теперь наша программа знает, что ему нужно будет получать две строки и вернуть номер. Компилятор может использовать эту информацию для броска ошибок, когда мы получаем ошибку типа … перед выполнением времени.

getIndexOf('Typescript', 'script'); // 4
getIndexOf(42, 'script'); // Argument of type '42' is not assignable to parameter of type 'string'.

Может быть, для небольших проектов (или небольших функций, таких как наши), мы на самом деле не видим слишком много выгоды.

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

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

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

Все примеры я покажу здесь, можно скопировать и бегать в TeampScript Playground Чтобы понять компилятор и результат процесса компиляции (ака «JavaScript» ).

В TearchScript у нас есть два разных вселенных: значение и пробелы типа. Пространство типа – это то, где типа определяются и используются для того, чтобы позволить компилятору делать всю великую магию. И стоимое пространство – это значения в наших программах, таких как переменные, константы, функции, знаковые литералы и вещи, которые мы имеем во время выполнения.

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

Teadercript имеет процесс типа проверки типов исходных кода и видит, если все правильно и последовательно. И тогда он может скомпилировать JavaScript.

Поскольку эти две части отдельно, мы не можем использовать тип проверки во время выполнения. Только в «время компиляции». Если вы попытаетесь использовать тип в качестве значения, он бросит ошибку: Только относится к типу, но используется в качестве значения здесь Отказ

Давайте посмотрим примеры этой идеи.

Представьте, что мы хотим написать функцию под названием Покупка Где мы получаем способ оплаты и на основе этого метода мы хотим сделать некоторые действия. У нас есть кредитная карта и дебетовая карта. Давайте определим их здесь:

type CreditCard = {
  number: number;
  cardholder: string;
  expirationDate: Date;
  secutiryCode: number;
};

type DebitCard = {
  number: number;
  cardholder: string;
  expirationDate: Date;
  secutiryCode: number;
};

type PaymentMethod = CreditCard | DebitCard;

Эти типы в Тип пространства Так что он работает только в компиляционном времени. После того, как тип проверки этой функции компилятор удаляет все типы.

Если вы добавляете эти типы в игровую площадку TeampStry, выход будет только строгое определение «Используйте строгие»; Отказ

Идея здесь – действительно понять, что типы живут в Тип пространства и не будет доступен во время выполнения. Так что в нашей функции это невозможно сделать:

const purchase = (paymentMethod: PaymentMethod) => {
  if (paymentMethod instanceof CreditCard) {
    // purchase with credit card
  } else {
    // purchase with debit card
  }
}

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

Компилятор знает разницу между двумя пробелами и что тип Кредитные карты живет в Тип пространства Отказ

Детская площадка является очень крутым инструментом, чтобы увидеть выходной код вашего Typearcript Code. Если вы создаете новый объект кредитной карты, как это:

const creditCard: CreditCard = {
  number: 2093,
  cardholder: 'TK',
  expirationDate: new Date(),
  secutiryCode: 101
};

Компилятор вводит проверку его и выполните все магию, а затем он транкирует код TeampScript для JavaScript. И у нас это:

const creditCard = {
    number: 2093,
    cardholder: 'TK',
    expirationDate: new Date(,
    secutiryCode: 101
};

Тот же объект, но теперь только со значением и без типа.

Ограничения и сужение типа

Когда мы ограничим то, что мы можем сделать, легче понять, что мы можем сделать.

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

const half = x => x / 2;

Сколько способов эта функция может потерпеть неудачу? Представьте себе ряд возможных входов:

[
  null,
  undefined,
  0,
  '0',
  'TK',
  { username: 'tk' },
  [42, 3.14],
  (a, b) => a + b,
]

И какие результаты для ввода:

half(null); // 0
half(undefined); // NaN
half(0); // 0
half('0'); // 0
half('TK'); // NaN
half({ username: 'tk' }); // NaN
half([42, 3.14]); // NaN
half((a, b) => a + b); // NaN

У нас есть разные и неожиданные результаты здесь. Здесь ясно, что мы хотим номер, как половина Функция, делайте расчет, и отлично, это сделано! Но иногда мы не контролируем ввод или кодовую базу большие, или новые/незнакомые, и мы можем сделать эти маленькие ошибки.

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

const half = (x: number) => x / 2;

И с этой новой информацией, если мы назовем функцию с тестовыми случаями снова, у нас разные результаты:

half(null); // Argument of type 'null' is not assignable to parameter of type 'number'.
half(undefined); // Argument of type 'undefined' is not assignable to parameter of type 'number'.(
half(0); // 0
half('0'); // Argument of type '"0"' is not assignable to parameter of type 'number'.
half('TK'); // Argument of type '"TK"' is not assignable to parameter of type 'number'.
half({ username: 'tk' }); // Argument of type '{ username: string; }' is not assignable to parameter of type 'number'.
half([42, 3.14]); // Argument of type 'number[]' is not assignable to parameter of type 'number'.
half((a, b) => a + b); // Argument of type '(a: any, b: any) => any' is not assignable to parameter of type 'number'.

В основном компилятор расскажет нам, что только номер числа, в данном случае 0 Значение, является действительным входом, он будет компитен и позволяет запустить код. Мы сужаем тип ввода и допускаем только значение, которое мы действительно хотим для этой функции.

Но есть ли другие способы сужения типов в Typescript. Представьте, что у нас есть функция, которая принимает параметр, который может быть либо строкой, либо числом.

type StringOrNumber = string | number;

function stringOrNumber(value: StringOrNumber) {}

В корпусе функции компилятор не узнает, какие методы или свойства мы можем использовать для этого типа. Это строка или номер? Мы только знаем о стоимости во время выполнения. Но мы можем сузить тип, используя Тип :

function stringOrNumber(value: StringOrNumber) {
  if (typeof value === 'string') {
    // value.
		// your ide will show you the possible methods from the string type
		// (parameter) value: string
    value
  }

  if (typeof value === 'number') {
    // value.
		// your ide will show you the possible methods from the number type
		// (parameter) value: number
    value
  }
}

С Если заявление и Тип Мы можем дать больше информации для компилятора. Теперь это будет знать конкретный тип для каждого Если тело.

IDE знает, что показать для конкретного типа. Во время выполнения, когда значение является строкой, он пойдет на первую Если Заявление, и компилятор выводится, что тип – это строка: (параметр) Значение: строка Отказ

Когда значение является числом, он пойдет ко второму Если Заявление и компилятор выводят, что тип – это номер: (параметр) Значение: номер Отказ

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

Другой пример, когда у нас есть необязательное свойство в объекте, но в функции нам нужно вернуть значение на основе этого дополнительного значения.

Представьте, что у нас есть этот тип:

type User = {
  name: string;
  address: {
    street: string;
    complement?: string;
  }
};

Это простой Пользователь тип. Давайте сосредоточимся на Дополнение имущество. Это необязательно (посмотрите, как | символ), что означает, что это может быть строка или undefined Отказ

Теперь мы хотим создать функцию для получения пользователя и получить длину дополнения адреса. Как насчет этого?

function getComplementLength(user: User): number {
  return user.address.complement.length;
	// (property) complement?: string | undefined
  // Object is possibly 'undefined'.
}

Как мы видим ранее, Дополнение может быть строка или undefined Отказ undefined на самом деле не имеет свойства под названием Длина :

Uncaught TypeError: Cannot read property 'length' of undefined

Мы могли бы сделать что-то вроде:

function getComplementLength(user: User) {
  return user.address.complement?.length;
}

Если Дополнение имеет строковое значение, мы можем позвонить Длина , в противном случае это вернется undefined Отказ

Таким образом, эта функция имеет два возможных типа возврата: Номер |. undefined Отказ Но мы хотим, чтобы мы вернулись только Номер Отказ Итак, мы используем Если или тройное условие, чтобы сузить тип. Это позвонит только Длина Когда он имеет реальную ценность (или когда это не undefined ).

function getComplementLength(user: User): number {
  return user.address.complement
    ? user.address.complement.length
    : 0;
}

Если это undefined Мы возвращаем минимальную длину: 0 Отказ Теперь мы можем использовать функцию с дизайном правильного типа с дополнением и без. Без компиляции и ошибок выполнения.

getComplementLength({
  name: 'TK',
  address: {
    street: 'Shinjuku Avenue'
  }
}); // 0

getComplementLength({
  name: 'TK',
  address: {
    street: 'Shinjuku Avenue',
    complement: 'A complement'
  }
}); // 12

Мы получим 0 от первого вызова функции и 12 от второго вызова.

С этим Если Концепция, мы также можем использовать другие помощники, чтобы сделать то же самое. Мы могли бы использовать в Оператор для проверки недвижимости от объекта, A Array.isarray проверить массив или Instanceof Для любого другого класса типа.

Мы также можем использовать более продвинутые концепции, такие как функция утверждения или типа охранников, но я оставлю эти концепции на будущие сообщения.

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

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

let email = 'harry.potter@mail.com';
email // 'harry.potter@mail.com'
email = 'hermione.granger@mail.com';
email // 'hermione.granger@mail.com'

Теперь представьте, что у вас есть список номеров. И вы хотите использовать функцию, чтобы суммировать все его номера. Функция выглядит так:

function sumNumbers(numbers: number[]) {
  let sum = 0;
  let num = numbers.pop();

  while (num !== undefined) {
    sum += num;
    num = numbers.pop();
  }

  return sum;
}

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

const list = [1, 2, 3, 4];
sumNumbers(list); // 10

Но что случилось с вашим списком? Функция действительно мутация это полностью?

list; // []

Если мы используем список, теперь он пуст. поп В Sumnumbers Функция – это функция «мутата». Это получает ссылки и удаляет предмет из них. Это не копия, это реальная ссылка.

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

Но с помощью TypeScript мы можем предоставить неизменность в компиляционном времени. Если вы не используете типы, можно использовать утверждение типа Как const Отказ Представьте себе это:

const author = {
  name: 'Walter Isaacson',
  email: 'walter.isaacson@mail.com',
  books: [
    {
      title: 'Leonardo Da Vinci',
      price: 50.00,
    }
  ]
};

author.books.push({
  title: 'Steve Jobs',
  price: 10.00
});

Просто объект автора, а затем мы добавляем новую книгу к этому автору. толчок Метод обновляет ссылку на массив книги. Это метод «мутата». Давайте посмотрим, используете ли вы утверждение Const Как const :

const author = {
  name: 'Walter Isaacson',
  email: 'walter.isaacson@mail.com',
  books: [
    {
      title: 'Leonardo Da Vinci',
      price: 50.00,
    }
  ]
} as const;

author.books.push({
  title: 'Steve Jobs',
  price: 10.00
});
// Property 'push' does not exist on type
// 'readonly [{ readonly title: "Leonardo Da Vinci"; readonly price: 50; }]'

Компилятор не скомпировался. Это получает ошибку на объекте автора. Это сейчас готов, и как отреадиальный объект, он не имеет никакого метода, называемого толчок (или любой метод «мутата»).

Мы добавили ограничение на объект автора. До этого был определенный тип (со всеми «мутатами» методами), и теперь мы сузили тип, чтобы быть почти одинаковым, но без «мутата» методов. Введите сужение.

Чтобы продолжить, давайте добавим типы на этот объект. книга и Автор :

type Book = {
  title: string;
  price: number;
};

type Author = {
  name: string;
  email: string;
  books: Book[];
};

Добавьте тип к объекту автора:

const author: Author = {
  name: 'Walter Isaacson',
  email: 'walter.isaacson@mail.com',
  books: [
    {
      title: 'Leonardo Da Vinci',
      price: 50.00,
    }
  ]
};

Добавьте тип в новый объект книги:

const book: Book = {
  title: 'Steve Jobs',
  price: 30
};

И теперь мы можем добавить новую книгу автору:

author.name = 'TK';
author.books.push(book);

Это работает просто хорошо!

Я хочу показать другой способ добавить неизменность в компиляционном времени. Tymdercript имеет тип утилиты под названием Readly Отказ

Вы можете добавить readly Для каждого свойства в объекте. Что-то вроде этого:

type Book = {
  readonly title: string;
  readonly price: number;
};

Но это может быть очень повторяется. Таким образом, мы можем использовать Readly Утилита для добавления readly Для всех свойств объекта:

type Book = Readonly<{
  title: string;
  price: number;
}>;

Одним из них следует помнить, так это то, что он не добавляет готовлю для вложенных свойств. Например, если мы добавим Readly к Автор Тип, это не добавит readly к Книга Тип тоже.

type Author = Readonly<{
  name: string;
  email: string;
  books: Book[];
}>;

Все свойства от автора не могут быть переназначены, но вы можете мутировать Книги Список здесь ( push , pop , …) Потому что Книга [] не готов Давай увидим это.

const author: Author = {
  name: 'Walter Isaacson',
  email: 'walter.isaacson@mail.com',
  books: [
    {
      title: 'Leonardo Da Vinci',
      price: 50.00,
    }
  ]
};

const book: Book = {
  title: 'Steve Jobs',
  price: 30
};

author.books.push(book);
author.books;
/* =>
 *
 * [
 *   {
 *     title: 'Leonardo Da Vinci',
 *     price: 50.00,
 *   },
 *   {
 *    title: 'Steve Jobs',
 *    price: 30
 *   }
 * ]
 *
 */

толчок будет работать просто хорошо.

Итак, как мы принудим для чтения для Книги ? Нам нужно убедиться, что массив является чтенным типом. Мы можем использовать Readly или использовать другую утилиту из Typeycript под названием Readonlyarray Отказ Давайте посмотрим два способа сделать это.

С Readly :

type Author = Readonly<{
  name: string;
  email: string;
  books: Readonly;
}>;

С Readonlyarray :

type Author = Readonly<{
  name: string;
  email: string;
  books: ReadonlyArray;
}>;

Для меня оба работа велико! Но на мой взгляд, Readonlyarray Более семантировано, и я также чувствую, что это меньше многословного (не то, что readonly с массивом).

Что случилось, если мы попытаемся мутировать объект автора сейчас?

author.name = 'TK'; // Cannot assign to 'name' because it is a read-only property.
author.books.push(book); // Property 'push' does not exist on type 'readonly [{ readonly title: "Leonardo Da Vinci"; readonly price: 50; }]'.

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

Семантика и читаемость

Сначала я почувствовал, что Teadncript может быть очень многослойным из-за типов и сделать код гораздо более сложным, чем он должен быть. И это на самом деле может. Стремиться к простоте – это цель, и в то же время трудно.

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

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

Представьте, что вам нужно добавить строку в SessionStorage Чтобы сохранить его в браузере. Ваша функция выглядит так:

function saveMyString(value: string): any {
  sessionStorage.myString = value;
}

Вы добавляете аннотацию типа на ввод строки и, как вы не знаете о возвращении, вы, вероятно, добавляете любой тип.

Но в чем реальный смысл этого возвращающегося типа? Это возвращает что-нибудь?

Это просто экономит строку к SessionStorage Отказ Это ничего не возвращает. пустота Тип был то, что вы ищете. По словам Tymdscript Docs: Отсутствие иметь любой тип вообще Отказ

function saveMyString(value: string): void {
  sessionStorage.myString = value;
}

Отлично, смысл типа правильный сейчас. Правильность очень важна в системе типа. Это способ моделировать наши данные, но и помочь поддерживать системы для будущих разработчиков. Даже если разработчик … ты!

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

Для некоторых кода нам не нужно явно добавлять аннотацию типа. Компилятор Typeyctry поймут и вывод неявно. Например:

const num: number = 1;

Этот код избыточно. Мы можем просто позволить компилятору использовать это так:

const num = 1;

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

Когда я узнал это, я подумал с собой. Но одно из крупнейших преимуществ использования SyperiCScript (или любого другого языка типа/статического типа типа) являются типы в качестве документации. Если мы позволим компилятору привести к выводу большинство типов, у нас не будет документации, которую мы хотим.

Но если вы наведите курсор на Typeycript в своем редакторе (по крайней мере VS-код работает так), вы можете увидеть информацию о типах и соответствующей документации.

Давайте посмотрим другие примеры избыточного кода и сделайте код менее Verbose и позвольте компилятору работать для нас.

function sum(a: number, b: number): number {
  return a + b;
};

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

function sum(a: number, b: number) {
  return a + b;
};

Неявный код, но с документацией, а компилятор делает работу.

Тип выделения работает для методов тоже:

function squareAll(numbers: number[]): number[] {
  return numbers.map(number => number * number);
};

Эта функция получает список чисел и делает каждое число в квадрате. Возвратный тип – Номер [] Несмотря на то, что результат карты всегда является списком, и, поскольку у нас есть список чисел, он всегда будет список номеров. Поэтому мы позволим компилятору использовать это тоже:

function squareAll(numbers: number[]) {
  return numbers.map(number => number * number);
};

Это работает так же для объектов.

const person: { name: string, age: number } = {
  name: 'TK',
  age: 24
};

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

const person = {
  name: 'TK',
  age: 24
};

Если вы паритете человек Вы получаете это:

const person: {
  name: string;
  age: number;
}

Типы здесь документированы.

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

function sum(a: number, b: number): number {
  return a + b;
};

Вместо того, чтобы вернуть номер суммы, мы хотим вернуть «Сумма: {A + B}» Отказ Так для А и B У нас есть результирующая строка как «Сумма: 3» Отказ

function sum(a: number, b: number): string {
  return `Sum: ${a + b}`;
};

sum(1, 2); // Sum: 3

Большой! Но теперь позвольте компилятору использовать это.

// function sum(a: number, b: number): number
function sum(a: number, b: number) {
  return a + b;
};

// function sum(a: number, b: number): string
function sum(a: number, b: number) {
  return `Sum: ${a + b}`;
};

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

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

В вашем приложении узла или приложении Frontend вы, возможно, сделаете некоторые извлечение для запроса данных. Вы обычно используете объект Fetch для выполнения запроса, а иногда вам нужно пройти заголовки приема.

fetch('/pokemons', {
  headers: {
    Accept: 'application/json'
  }
});

fetch('/harry-potter/spells', {
  headers: {
    Accept: 'application/json'
  }
});

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

enum MediaTypes {
  JSON = 'application/json'
}

fetch('/pokemons', {
  headers: {
    Accept: MediaTypes.JSON
  }
});

fetch('/harry-potter/spells', {
  headers: {
    Accept: MediaTypes.JSON
  }
});

И мы можем добавить больше данных, связанные с Медиативы как PDF :

enum MediaTypes {
  JSON = 'application/json',
  PDF = 'application/pdf'
}

С Enum мы можем инкапсулировать данные в значимый блок кода.

Недавно я реализовал «государственный» комментарий реагирования. Это в основном компонент, который отображает пустое состояние или состояние ошибки на основе ответа запроса.

UI для пустых и состояний ошибок были очень похожи. Только заголовок и текст описания и значок изображения были разными. Итак, я подумал: «У меня есть два способа реализовать это: выполнить логику вне компонента и пройти всю необходимую информацию или пропустить« тип состояния »и позволить компоненту рендерировать правильный значок и сообщения».

Итак, я построил enum:

export enum StateTypes {
  Empty = 'Empty',
  Error = 'Error'
};

И я мог бы просто передать эти данные к компоненту как Тип :

import ComponentState, { StateTypes } from './ComponentState';



В компоненте у него был государственный объект со всей информацией, связанной с Название , Описание и Значок Отказ

const stateInfo = {
  Empty: {
    title: messages.emptyTitle,
    description: messages.emptyDescription,
    icon: EmptyIcon,
  },
  Error: {
    title: messages.errorTitle,
    description: messages.errorDescription,
    icon: ErrorIcon,
  },
};

Так что я мог бы просто получить тип на основе Enum и использовать этот Условие объект с Государство Компонент из нашей системы дизайна:

export const ComponentState = ({ type }) => (
  
);

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

Другая прохладная особенность из TypeyctScript является необязательными свойствами. Когда у нас есть свойства от объекта, который может быть реальным значением или неопределенным, мы используем необязательное свойство, которое будет явно, что свойство может быть или не быть там. Синтаксис для этого простой ? Оператор в объекте свойства. Представьте себе эту функцию:

function sumAll(a: number, b: number, c: number) {
  return a + b + c;
}

Но теперь C Значение необязательно:

function sumAll(a: number, b: number, c?: number) {
  return a + b + c;
}

Мы добавляем ? после C Отказ Но теперь у нас есть ошибка компилятора:

(parameter) c: number | undefined
Object is possibly 'undefined'.

Мы не можем суммировать undefined Значение (ну на самом деле в JavaScript мы можем, но мы получаем NAN Value).

Нам нужно обеспечить, чтобы C существуют. Введите сужение!

function sumAll(a: number, b: number, c?: number) {
  if (c) {
    return a + b + c;
  }

  return a + b;
}

Если C существует, это будет Номер И мы можем суммировать все. Если нет, сумма только А и B значения.

Интересная часть этого дополнительного свойства заключается в том, что это undefined не null Отказ Вот почему мы делаем это, мы получаем ошибку компиляции:

let number = null;
sumAll(1, 2, number);
// Argument of type 'null' is not assignable to parameter of type 'number | undefined'.

Как ? Оператор не обрабатывает null Значение, выберите, чтобы использовать undefined Введите ваше приложение и поэтому вы все равно можете использовать дополнительное свойство и сделать типы последовательными. Мы можем использовать это так:

let value: number | undefined;
sumAll(1, 2, value); // 3

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

function sumAll(a: number, b: number, c: number = 3) {
  return a + b + c;
}

Дополнительные свойства не только работает на переменных и параметрах, но и в объектах.

Ответ API является хорошим примером определения типа и дополнительного свойства вместе. В ответах API данные могут быть необязательными. Иногда API отправляет, иногда не имеет значения.

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

Представьте, что мы выбираем пользовательские данные, и это так, как мы смоделировали тип ответа:

type UserResponse = {
  name: string;
  email: string;
  username: string;
  age: number;
  isActive: boolean;
};

Но на самом деле электронное письмо необязательно для пользователя. Конечная точка API может вернуться или нет. Но Userresponse Тип, который мы построили обрабатываем его как требуемое свойство.

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

function matchDomain(email: string) {
  return email.endsWith(domain);
}

Как Email Недвижимость требуется в Userresponse Тип, Email Параметр также потребуется в Matchdomain функция.

Это время выполнения, которое мы можем получить, если Email это undefined :

// Uncaught TypeError: Cannot read property 'endsWith' of undefined

Но что бы произошло, если мы смоделировали Userresponse правильно?

type UserResponse = {
  name: string;
  email?: string;
  username: string;
  age: number;
  isActive: boolean;
};

Теперь Email возможно undefined И это явно.

Но если мы все еще будем держать функцию Matchdomain Так же, мы получаем сообщение с компиляцией:

// Argument of type 'undefined' is not assignable to parameter of type 'string'.

И это здорово! Теперь мы можем исправить Email Параметр в этой функции с использованием ? Оператор:

function matchDomain(email?: string) {
  return email.endsWith('email.com');
}

Но теперь мы получаем сообщение с компиляцией при запуске Email.endswith потому что это может быть undefined тоже:

// (parameter) email: string | undefined
// Object is possibly 'undefined'.

Введите сужение! Мы используем его блок для возврата ложь Когда Email это undefined Отказ И беги Эндонсвит Способ только если Email действительно строка:

function matchDomain(email?: string) {
  if (!email) return false;
  return email.endsWith('email.com');
}

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

Тип композиции

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

Одним из примеров композиции, которого я всегда должен обрабатывать с помощью Redux или Успеведщик Крюк от реагирования – это идея «редукторов». Редуктор всегда может получить ряд различных действий.

В этом контексте действия являются объектами, по крайней мере, A Тип имущество. Похоже, это выглядит:

enum ActionTypes {
  FETCH = 'FETCH'
}

type FetchAction = {
  type: typeof ActionTypes.FETCH;
};

const fetchAction: FetchAction = {
  type: ActionTypes.FETCH
};

А Fetchaction имеет тип Fetchaction у этого есть тип свойств, который является типом Извлекать Отказ

Но редуктор может получить другие действия тоже. Например A отправка действий:

enum ActionTypes {
  FETCH = 'FETCH',
  SUBMIT = 'SUBMIT'
}

type SubmitAction = {
  type: typeof ActionTypes.SUBMIT;
};

const submitAction: SubmitAction = {
  type: ActionTypes.SUBMIT
};

Для определенного контейнера мы можем сочинять все эти действия только на одном типе и использовать его для типа параметра редуктора.

Это будет выглядеть так:

type Actions = FetchAction | SubmitAction;

function reducer(state, action: Actions) {
  switch (action.type) {
    case ActionTypes.FETCH:
    // fetching action
    case ActionTypes.SUBMIT:
    // submiting action
  }
}

Все возможные действия являются Действия тип. И мы используем тип Union для «присоединиться» всех типов действий. Действие в редукторе может иметь Fetchaction или Отправка Отказ

Как гонтер, я не мог пропустить пример Гарри Поттера. Я хочу построить простую функцию, чтобы выбрать дом Хогвартса, основанный на черте человека. Давайте сначала начнем с домов.

type House = {
  name: string;
  traits: string[];
}

const gryffindor: House = {
  name: 'Gryffindor',
  traits: ['courage', 'bravery']
};

const slytherin: House = {
  name: 'Slytherin',
  traits: ['ambition', 'leadership']
};

const ravenclaw: House = {
  name: 'Ravenclaw',
  traits: ['intelligence', 'learning']
};

const hufflepuff: House = {
  name: 'Hufflepuff',
  traits: ['hard work', 'patience']
};

const houses: House[] = [
  gryffindor,
  slytherin,
  ravenclaw,
  hufflepuff
];

Я хочу держать это просто, поэтому Дом Тип имеет только Имя и Черты , список возможных черт от людей, связанных с домом.

А потом я создаю каждый дом и добавил все их на Дома список.

Большой! Теперь я построю Человек тип. Человек может быть ведьмой или маглов.

type Witch = {
  name: string;
  trait: string;
	magicFamily: string;
}

type Muggle = {
  name: string;
	trait: string;
  email: string;
}

И это часть, которую мы объединяем эти два разных типа, используя тип профсоюза:

type Person = Muggle | Witch;

Использование типа пересечения, Человек Тип имеет все свойства от Маггл Или все от Ведьма Отказ

Так что теперь, если я создаю Маггл Мне нужно только имя, черту и электронное письмо:

const hermione: Muggle = {
  name: 'Hermione Granger',
	trait: 'bravery',
  email: 'hermione@mail.com'
};

Если я создаю Ведьма Мне нужно имя, черта и магическое имя семьи:

const harry: Witch = {
  name: 'Harry Potter',
  trait: 'courage',
  magicFamily: 'Potter'
};

И если я создаю Человек Мне нужно хотя бы Имя и Черта Недвижимость от Маггл и Ведьма :

const tk: Person = {
  name: 'TK',
  email: 'tk@mail.com',
  trait: 'learning',
  magicFamily: 'Kinoshita'
};

Выбор очень просто Мы просто Pas домов и человек. Основываясь на черте человека, функция вернет выбранный дом:

function chooseHouse(houses: House[], person: Person) {
  return houses.find((house) => house.traits.includes(person.trait))
}

И применяя все люди, которые мы создали:

chooseHouse(houses, harry); // { name: 'Gryffindor', traits: ['courage', 'bravery'] }
chooseHouse(houses, hermione); // { name: 'Gryffindor', traits: ['courage', 'bravery'] }
chooseHouse(houses, tk); // { name: 'Ravenclaw', traits: ['intelligence', 'learning'] }

Хороший!

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

Когда я реализовал веб-приложение для Примените мои исследования на UX , Мне нужно было создать тип опоры для компонента изображения.

У меня был тип Imageurl Из типов продукта:

type ImageUrl = {
  imageUrl: string;
};

И Imageattr Чтобы представлять все атрибуты для изображения:

type ImageAttr = {
  imageAlt: string;
  width?: string
};

Но реквизиты ожидали всю эту информацию в компоненте. Тип пересечения для спасения!

type ImageProps = ImageUrl & ImageAttr;

Просто как тот. Так что теперь компонент нуждается в всех этих свойствах. Тип выглядит так:

type ImageProps = {
  imageUrl: string;
  imageAlt: string;
  width?: string
};

И мы можем использовать этот тип таким образом:

const imageProps: ImageProps = {
  imageUrl: 'www.image.com',
  imageAlt: 'an image',
};

const imagePropsWithWidth: ImageProps = {
  imageUrl: 'www.image.com',
  imageAlt: 'an image',
  width: '100%'
};

Хороший! Еще одна концепция для повторного использования и составных типов.

Я также нахожу Выберите Тип очень интересный и полезный. У нас есть другие Интересные виды Что мы могли бы написать здесь, но идея здесь состоит в том, чтобы понять, что мы можем составить тип, и нет ограничений для повторного использования типов. Если вы заинтересованы в изучении других типов, посмотрите на этот пост, я писал: Shotescript Sentitions: интересные типы Отказ

Инструмент

Когда ты NPM установить TypeScript , Вы не просто получаете компилятор, вы получаете API Language Service, автономный сервер под названием TSSERVER, которые редакторы могут работать, чтобы предоставить автозаполнение, GO-TO-TO и другие крутые функции.

Эти функции – это то, что некоторые люди из Teamecript Team Country вызывают инструменты производительности разработчиков, такие как интеллектуальные ошибки при проверке и Intellisense (завершение кода, информация на курсе, информация о подписи). Мы посмотрим на эти функции на протяжении всей всей статьи, но я хочу сделать особую тему, чтобы поговорить об этом.

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

const city = 'Tokyo';
city.toUppercase();
// Property 'toUppercase' does not exist on type
// 'string'. Did you mean 'toUpperCase'?

В этом случае компилятор действительно умный, потому что он точно находит то, что мы хотели.

Это также работает для объектов:

const people = [
  { name: 'TK', age: 24 },
  { name: 'Kaio', age: 12 },
  { name: 'Kazumi', age: 31 },
];

for (const person of people) {
  console.log(person.agi);
  // Property 'agi' does not exist on type '{ name: string; age: number; }'
}

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

Если вы напечатаете: «ТК». Редактор покажет все возможные методы для строкового объекта. Компилятор знает, что это строка. И это знает методы из Строка опытный образец. Но это также обеспечивает подпись метода. Это очень интересно, потому что мы не обязательно должны идти в документы. «Документы» уже в нашем редакторе кода.

Это потрясающий опыт во время кодирования.

Определение типа «на Hover» – это другое, что мы видели ранее в этой статье. Позвольте компилятору неявно выводят типы, и вы не потеряете документацию типа. Используя наведите курсор в объект, IDE или редактор всегда смогут показать определение типа.

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

Представьте, что у нас есть функция, чтобы открыть закуска, если она все еще закрыта. Это проверило бы состояние закуски. Если он закрыт, просто позвоните другую функцию, чтобы открыть его.

const buildSnackbar = (status: SnackbarStatus) => {
  if (status.isClosed) {
    openSnackbar();
  }
};

И информация о типе для этого закускана:

type SnackbarStatus = {
  isClosed: boolean;
};

Что произойдет, если я называю эту функцию, как это:

buildSnackbar({ isclosed: true });

Это не сломается во время выполнения, потому что Статус Объект не имеет раскрывается атрибут и undefined Объект – это Falsy Значение, так что это будет пропустить, если состояние и не позвонит opensnackbar функция. Нет ошибки времени выполнения. Но, вероятно, это будет поведение, отличное от ожидаемого.

В Teadercript компилятор даст некоторые советы, чтобы сделать его правильно. Сначала это покажет эту ошибку:

// Argument of type '{ isclosed: boolean; }' is not assignable to
// parameter of type 'SnackbarStatus'.

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

Второй еще лучше:

// Object literal may only specify known properties,
// but 'isclosed' does not exist in type 'SnackbarStatus'.
// Did you mean to write 'isClosed'?

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

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

Мое предложение, чтобы узнать больше об этом – просто код в Teadercript и «разговор» с компилятором. Прочитайте ошибки. Играть с париком. Увидеть автозаполнение. Понять метод подписи. Это действительно производительный способ кода.

Советы и учащиеся

Когда статья подходит к концу, я хочу просто добавить некоторые окончательные мысли, учащиеся и советы, которые помогут вам помочь вам в вашем путешествии в Teamplection или просто применять его в ваших проектах.

  • Действительно прочитайте ошибку типа: это поможет вам лучше понять проблему и типы.
  • strictnullchecks и NoMplicitalaNy может быть очень полезен в поисках ошибок. Включите это как можно скорее в вашем проекте. Использовать strictnullchecks Для предотвращения «undefined не является объектом» ошибки времени выполнения. Использовать NoMplicitalaNy Чтобы ввести исходный код, чтобы получить больше информации для компилятора.
  • Вместе с конфигурациями компилятора я всегда рекомендую быть очень точным о ваших типах. В основном со значениями, которые происходят только во время выполнения, такие как ответ API. Правильность важно поймать как можно больше ошибок в компиляции.
  • Понять разницу между временем выполнения и временем компиляции: типы влияют только в типе компиляции. Он запускает тип проверки типа, а затем компилирует JavaScript. Исходный код JavaScript не использует какие-либо типы ссылок или операций типа.
  • Узнайте о типах утилит. Мы говорили более конкретно о Readly В неизменности в компиляционном времени, но есть коробка помощников, таких как Требуется , Выберите и многое другое.
  • Если возможно, предпочитайте позволить компилятору активизировать типы для вас. Большинство типов и возвратных типов являются избыточными. Компилятор Tymdercript очень умны в этой области. Если невозможно, вы всегда можете добавить аннотации типа. И оставьте утверждения типа как последний вариант.
  • Как вы пишете код, посмотрите на инструмент. Дизайн инструмента, предусмотренного в IDE, удивительно. Проверка IntelliSense и Type предоставляет действительно хороший опыт.

Этот пост был изначально опубликован в Блог Tk Отказ И вы можете найти больше контента, как это в моем блоге на https://leandrotk.github.io/tk Отказ

Вы также можете следовать за мной на Twitter и Github Отказ

Я скомпилировал (PAL очень предназначен!) Куча ресурсов, которые помогут вам узнать больше о языках программирования, типами типами.

Кроме того, если вы нашли примеры на этом посте полезны, я добавил все из них этот репозиторий: Мышление в видах Отказ Так что вы можете вилоть и играть с ним.

Тип системы

Опыт инструментов и разработчика

Время компиляции против времени выполнения

Лучшие практики

Книги