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

Дэвидом Piepgrass быстрый, но в глубине TypeScripts и его типовых типов, дженерики, JSX, системные лазейки типа и многое другое! Фото Луиса Вильясмилия на Unsplashthits Quick Tour по ThreectScript в основном для людей, которые имеют некоторый опыт работы с JavaScript. Я объясню несколько удивительных фактов о JavaScript,

Дэвидом Piepgrass быстрый, но в глубине TypeScripts и его типовых типов, дженерики, JSX, системные лазейки типа и многое другое! Фото Луиса Вильясмилия на Unsplashthits Quick Tour по ThreectScript в основном для людей, которые имеют некоторый опыт работы с JavaScript. Я объясню несколько удивительных фактов о JavaScript,

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

Дэвидом Piepp

Типы профсоюзов, дженерики, JSX, системные лазейки типа и многое другое!

Этот быстрый экскурсию на Tymdscript в основном для людей, у которых есть опыт работы с JavaScript.

Я объясню несколько удивительных фактов о JavaScript, если вы изучали только что-то смутно, как Java или C #. Если вы хотите знать, как настроить напечатанный проект, см. Мой Предыдущая статья Отказ

Teadercript основан на JavaScript. Typlectry Compiler (или другие инструменты, основанные на нем, как TS-NODE или TS-JEST ) Переводят в обычный JavaScript, просто заменив все данные типа.

Наряду с этим процессом выполняется проверка типа, чтобы обнаружить Тип ошибок – ошибки, которые вы сделали, чтобы иметь что-то с видами. Конечно, иногда это также жалуется на то, что вы намеренно сделали, тем не менее сломали правила Typeyctry.

Типы

Типы могут быть прикреплены к переменным с толстой кишкой (:) в их определении, как так:

let z: number = 26;

Однако вам часто не нужно Запишите тип. Например, если вы пишете:

let z = 26;

Tymdercript МИЗКИ что Z – число. Так что если вы пишете:

let z = 26;z = "Not a number";

Вы получите ошибку во второй строке. Typeyctry Первоначально принял лазейку, хотя: любая переменная может быть null или undefined :

z = null;      // Allowed!z = undefined; // Allowed! 

Если вы новичок в JavaScript, вы, вероятно, задаетесь вопросом, что null и undefined или Почему они две разные вещи Отказ

Ну, я обещал рассказать вам о Tymdercript и null / undefined являются JavaScript вещи. ДА!

Лично я не пользуюсь null очень. Мне удобно использовать undefined последовательно, чтобы не беспокоиться о различии. undefined это значение по умолчанию новых переменных и параметров функций, которые не были предоставлены абонентом. Это значение, которое вы получаете, если вы прочитаете свойство, которое не существует на объекте. Напротив, сам JavaScript только редко использует null Поэтому, если вы не используете его самостоятельно, вы не будете сталкиваться с этим очень часто. Я уверен, что некоторые люди делают обратное и предпочитают null Отказ

Во всяком случае, некоторые люди, в том числе я – считают, что позволяют каждый переменная быть null / undefined была плохой идеей. Так что Typeycript 2.0 Позволяет забрать, что разрешение с "Strictnullchecks": правда Опция компилятора в “tsconfig.json”. Вы можете использовать «Строгий»: правда Для проверки максимального типа. Вместо этого вы бы написали:

let z: number | null = 26;

Если вы хочу z быть потенциально null (| означает «или»).

Типы союза

Tymdercript имеет возможность понимать переменные, которые могут иметь несколько типов. Например, вот какой-то нормальный код JavaScript:

Это разрешено в Teadercript по умолчанию, потому что var y (сам по себе) дает y Тип любой , что-либо значение. Таким образом, мы можем назначить что-либо, например, значение или объект, чтобы y Отказ Мы, безусловно, можем установить его в строку или номер или массив двух вещей. любой Это специальный тип – это означает «это значение или переменную должно действовать как значение JavaScript или переменной, и, следовательно, не дайте мне никаких ошибок типа».

Я рекомендую «Строгий»: правда опция компилятора. Но в этом режиме TypeScript не позволяет var y – Это требует var y: любой вместо.

Однако TypeScript позволяет нам быть более конкретным, говоря:

var y: string | number;

Это означает, что «переменная y – это строка или число». Если y Создан таким образом, используя пример выше, Если-ж Часть разрешена. Но другая часть, которая говорит y = [y, y] не допускается, потому что [Y, Y] это не строка, а не число либо. y это массив типа Номер [] | строка [] Отказ Эта функция, в которой переменная может иметь один из двух (более) типов, называется Типы союза И это часто полезно.

Совет: Чтобы помочь вам изучить TypectScript, это может помочь Есть ли эксперименты на детской площадке Отказ Чтобы помочь вам узнать больше о JavaScript , нажмите F12 в Chrome, Firefox или Edge и ищите консоль. В консоли вы можете написать код JavaScript, чтобы узнать, что делает небольшой кусок JavaScript и правильно ли вы пишете:

Эта консоль фантастика, потому что вы можете использовать его для проведения экспериментов в любой Вкладка браузера – даже этот! Поскольку Skyscript – это просто JavaScript со статической проверкой типа, вы можете использовать консоль, чтобы помочь вам узнать о части TeampScript, что не есть статические типы. В вашем файле TypeyctS вы можете позвонить console.log (что-то) Напечатать вещи в консоли браузера. В некоторых браузерах Журнал Можно отображать сложные объекты. Например, попробуйте написать Console.log ({Название: "Стив", Возраст: 37, Favoritenumbers: [7, 666, -1]}) :

Классы

Как вы знаете, классы – это пакеты функций и переменных, которые могут быть созданы на несколько объектов. Функции внутри классов могут ссылаться на другие функции и переменные внутри класса, но в JavaScript и Teamscript вы должны использовать префикс это. Типичный класс JavaScript может выглядеть так:

Вывод консоли:

The big box is 10000 times larger than the small oneThe zero-size box has an area of 0.

JavaScript немного тихо. Когда вы создаете функцию вне класса, он имеет слово Функция перед ней. Но, когда вы создаете функцию внутри Класс это не допускается иметь слово Функция перед ней.

Функции и методы одинаковы, за исключением того, что методы в классах имеют доступ к это – ссылка на текущий объект, кроме Статический методы. Статический Методы называются Класс , Box.zerosize В этом примере, поэтому у них нет «текущего объекта». (Ну, на самом деле текущий объект Zerosize – это коробка Функция конструктора, которая является не экземпляр коробка .)

В отличие от JavaScript, Tymdercript Classes позволяют переменные объявления, такие как ширина и Высота В этом примере:

Для удобства TypeScript позволяет определить конструктор и переменные, которые он инициализирует одновременно. Так вместо

  width: number;  height: number;  constructor(width: number, height: number) {    this.width = width;    this.height = height;  }

Вы можете просто написать

constructor(public width: number, public height: number) {}

Кстати, для любых разработчиков C #, читая это, это работает точно так же, как мой Система лемпы для C #.

В отличие от JavaScript, Tymdercript имеет Частныйзащищенные ) переменные и функции, которые недоступны за пределами класса:

Частный Переменные позволяют четко помечать части класса как «внутренний». Пользователи класса не могут изменить или прочитать их.

Интерфейсы

Интерфейсы – это способ описания «форм» объектов. Вот пример:

Ibox относится к любому классу, который имеет ширина и Высота Собственность, которые являются читаемыми номерами. IAREA относится к чему-либо читаемому область имущество. Коробка Класс удовлетворяет обоим этим требованиям. Получить область () Функция считается как свойство, потому что он называется без () круглые скобки. Так что я мог бы написать:

let a: IBox = new Box(10,100);  // OKlet b: IArea = new Box(10,100); // OK

Интерфейсы в типографии работают как интерфейсы в языке программирования GO, не похожи на интерфейсы в Java и C #. Это хорошая вещь. Это означает, что классы Не должны явно Скажите, что они реализуют интерфейс. Коробка Реализация Ibox и IAREA не говоря так.

Это означает, что мы можем определить интерфейсы для типов, которые первоначально не были предназначены для какого-либо конкретного интерфейса. Например, мой BTREE Пакет Определяет IMAP AL> Интерфейс, который представляет собой словарь пар клавишных пар. TH E N EW Map Class, встроенный в ES6, также соответствует этому интерфейсу, так что вы можете поставить карта в к N IMAP переменная. Так, например, вы можете написать функцию Wi a N IMAP параметр, а вы можете p задница карта или BTREE к функции, и функция не должна знать или позаботиться о том, какой тип получена.

readly Значит, мы можем прочитать, но не изменять:

console.log(`The box is ${a.width} by ${a.height}.`); // OKa.width = 2; /* ERR: Cannot assign to 'width' because it is a                      constant or a read-only property. */

Tymdercript не требует readly для интерфейсной совместимости. Например, TypeScript принимает этот код, даже если он не работает:

interface IArea {  area: number; // area is not readonly, so it can be changed}
let ia: IArea = new Box(10,100);ia.area = 5; // Accepted by TypeScript, but causes a runtime error

Я думаю об этом как об ошибке в Typescript.

Типрипечата также имеет концепцию дополнительных частей интерфейса:

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

Например, мы можем написать Пусть P: Person = {Название: 'Джон Доу', Возраст: 37} Отказ С P это Человек , мы можем позже обратиться к P.spouse. Это равно undefined В этом случае, но может быть Человек Если другой объект был назначен ему, что имеет Супруга Отказ

Однако, если вы используете P = {Название: «Чад», Возраст: 19, Супруга: «Дженнифер»} С неправильным типом данных для Супруга TypeScript отвечает, что Тип строки не является назначенной на тип человека |. undefined Отказ

Типы пересечений

Типы пересечений являются менее известным двоюродным братом профсоюзных типов. Тип профсоюза, как A |. B означает, что значение может быть либо А или б, но не оба. Тип пересечения, как A & B означает, что значение является как A и B одновременно. Например, это коробка это оба Ibox и IAREA Таким образом, у него есть все свойства из обоих интерфейсов:

let box: IBox & IArea = new Box(5, 7);

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

// either a Date&IArea or IBox&IArealet box1: (Date | IBox) & IArea = new Box(5, 7);// either a Date or an IBox&IArealet box2: Date | (IBox & IArea) = new Box(5, 7);

& имеет более высокий приоритет, чем |. Итак, A & B | C означает (A & B) | C Отказ

Структурные типы

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

var book1 = { title: "Adventures of Tom Sawyer",       year:1876 };var book2 = { title: "Adventures of Huckleberry Finn", year:1884 };

Если вы наведите курсор мыши на Книга1 В VS-коде его тип описан как {Название: строка; Год: номер; } Отказ Это структурные Тип: тип, определяемый полностью тем, что имеет свойство под названием Название который является строка и другое имущество под названием Год который является Номер Отказ Таким образом Книга1 и Книга2 иметь тот же тип, и вы можете назначить одно другому или другую книгу.

book1 = book2; // allowedbook2 = { year: 1995, title: "Vertical Run" }; // allowed

Вообще говоря, вы можете назначить значение с «большим количеством вещей» к переменной, тип которого включает в себя «меньше вещей», но не наоборот вокруг:

var book3 = { title: "The Duplicate",               author: "William Sleator", year:1988 };var book4 = { title: "The Boy Who Reversed Himself" };book1 = book3; // allowedbool1 = bool4; /* NOT allowed. Here is the error message:    Type '{ title: string; }' is not assignable to type     '{ title: string; year: number; }'. Property 'year'     is missing in type '{ title: string; }'.  */ 

Кроме того, если у нас есть такой интерфейс:

interface Book {  title: string;  author?: string;  year: number;}

Тогда мы можем назначить любой Книга ценность для либо Книга1 или Книга2 Отказ Но Автор требуется в Книга3 и Книга может не содержать автора. Мы можем назначить любую из переменных книги для новой переменной типа Книга , кроме Книга4 , конечно.

Очевидно, что структурные типы фантастические. Это очевидно после того, как вы проведете несколько лет, используя языки без них. Например, представьте, если два человека, Альфред и Барбара, напишите разные модули А и B Отказ Они оба занимаются точками с использованием координат X-Y. Таким образом, каждый модуль содержит Точка интерфейс:

interface Point {    x: number;    y: number;}

Многие языки используют Номинал Типы вместо структурных типов. На этих языках A.Point считается совершенно другим типом, чем B.Point Хотя они идентичны. Так что любые пункты, произведенные А не может быть использован B и наоборот. Это может быть разочаровывающим, поэтому, пожалуйста, найдите время, чтобы отпраздновать со мной у чудо структурного набора текста.

Структурные типы могут быть написаны либо с запятыми или запятыми, например {x: номер, номер y: номер} и {x: номер; Y: номер; } одинаковы.

Набор на основе потока и восклицательный знак

Если S это строка, вы могли бы написать S.match ( /[0-9] +/ ) Чтобы найти первую группу цифр в этой строке. /[0-9] +/ это Regexp – объект, который можно использовать для поиска строк, использующих Регулярные выражения Отказ Регулярные выражения представляют собой систему сопоставления строки, поддерживаемую многими языками программирования, включая JavaScript.

Матч Возвращает массив строк или null Если Regexp не соответствовал строке. Например, если S Тогда S.match (/[0-9] +/) Возвращает [«10»] , но если S Тогда Матч Возвращает null Отказ

Если вы искали цифры в строке, вы бы хотели, чтобы ваш код вести себя по-разному в зависимости от того, имеет ли строка цифр или нет, верно? Так что вы бы использовали Если утверждение:

var found: string[]|null = s.match(/[0-9]+/);if (found) {  console.log("The string has a number in it: " + found[0]);} else {  console.log("The string lacks digits.");}

Как вы, наверное, знаете, Если (найден) Средства «если найдено правда». Это в основном означает Если (найдено && найдено && найдено) Отказ

Если вы не проверяете ли Найдено TypeScript придаст вам ошибку:

var found = s.match(/[0-9]+/);console.log("The string has a number in it: " + found[0]);           // Error: Object is possibly 'null'  ^^^^^

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

В первой отрасли Если Заявление, Tymdercript знает, что Найдено не может быть нулевым, и поэтому тип Найдено изменения в этом блоке исключить null Отказ Таким образом, его тип становится строка [] Отказ Точно так же внутри еще {...} Блок, TeampScript знает, что Найдено не может быть строка [] Итак, строка [] исключен и тип Найдено становится null в этом регионе.

Но Typearcript имеет ! Оператор, который используется для избежания определенных сообщений об ошибках. Это означает «смотреть, компилятор, я знаю, что вы думаете, что эта переменная может быть NULL ИЛИ undefined , но я обещаю вам, что нет. Так что если найден имеет тип string [] | NULL , тогда найден! имеет тип строка [] . “

Если вы уверены, что S Имеет цифры в нем, вы можете использовать ! Чтобы избежать сообщения об ошибке:

var found = s.match(/[0-9]+/);console.log("The string has a number in it: " + found![0]);

Система печата на основе TypeyScript поддерживает Тип и Instanceof операторы, а также обычные операторы сравнения. Если вы начнете с переменной, которая может иметь несколько типов, вы можете использовать любой из этих операторов, чтобы сузить тип:

Примечание: JavaScript различает Примитивный и Максимальный примитивный Типы, которые являются объектами. Например, «пряжа» является примитивным, и его тип – строка Отказ Тем не менее, есть также коробка Тип строки под названием Строка с капиталом S, который редко используется. Вы можете создать Строка Письма Новая строка («пряжа») Отказ То, что нужно помнить, так это то, что это совершенно разные типы.

«пряжа» instanceof string это ложь : «пряжа» это строка , а не Строка !

«пряжа» instanceof string это не ложный. Вместо этого это абсолютно нелегальное выражение – правая часть Instanceof Должен быть Функция конструктора и строка не имеет конструктора.

JavaScript предоставляет два разных оператора для тестирования типов примитивов и объектов (не примитивов):

  • Instanceof проверяет Цепочка прототипа Чтобы узнать, является ли значение определенным видом объекта.
  • Тип Проверяет, является ли что-то примитивным и если да, то какой.

Как вы можете видеть в коде выше, Instanceof это двоичный оператор, который возвращает логию, а Тип это унарный оператор, который возвращает строку. Например, Тип «пряжа» Возвращает «Строка» и Тип 12345 Возвращает «Номер» Отказ Примитивные типы являются Номер , логический , строка , Символ , undefined и null Отказ Все, что не является примитивным, не является Объект , включая функции.

Но Тип относится к функциям специально. Например, typeof math.sqrt и Math.sqrt inductionOf Объект Отказ Символы новые в ES6 и, хотя null является примитивным, Тип NULL это ошибка Отказ

Как вы можете видеть в приведенном выше примере, TeampScript также понимает Array.isarray как способ обнаружить массив. Однако некоторые другие методы обнаружения типов в JavaScript не поддерживаются:

  • Если (вещь .unshift) иногда используется для различения строк от других вещей, потому что почти ничего, кроме строк, не имеют Неприносимость метод. Это не поддерживается в Teadercript, потому что он не позволяет читать свойство, которое может не существовать.
  • Если (вещь. HasownProperty («Неснесение»)) не распознается как тест типа.
  • Если (вещь. Инструктором) не распознается как тест типа. В JavaScript, чтение недвижимости, такого как Конструктор продвигает вещь к коробочному статусу, так что даже если вещь это Примитивная струна его .constructor будет не примитивный Отказ
  • Если («нести» на вещи) не работает. «Правая сторона выражения« в »должна быть типа« любой », тип объекта или параметр типа.” ( в следует избегать в любом случае, потому что это медленно.)

Тип псевдонимов

Тип Заявление создает новое имя для типа. Например, после написания:

type num = number;

Вы можете использовать Num Как синоним для Номер Отказ Тип похоже на Интерфейс Так как вы можете написать что-то вроде этого …

type Point = {    x: number;    y: number;}

… вместо Точка интерфейса {...} Отказ Однако только интерфейсы поддерживают наследование. Например, я могу создать новый интерфейс, который является как Точка Но также есть новый участник z , как это:

interface Point3D extends Point {    z: number;}

Вы не можете сделать наследство с Тип Отказ Однако если Точка был определен с Тип , вам все еще разрешается продлить это с Интерфейс Отказ

Типы функций

В JavaScript вы можете пропускать функции другим функциям, как это:

function doubler(x) { return x*2; }function squarer(x) { return x*x; }function experimenter(func){  console.log(`When I send 5 to my function, I get ${func(5)}.`);}experimenter(doubler);experimenter(squarer);

Выход:

When I send 5 to my function, I get 10.When I send 5 to my function, I get 25.

В Teamescript вы обычно должны записывать типы аргументов функций – вам нужно знать, как выразить тип Func Отказ Как вы можете видеть здесь, его тип должен быть что-то вроде (paral: номер) => num Бер:

function doubler(x: number) { return x*2; }function squarer(x: number) { return x*x; }function experimenter(func: (param: number) => number){  console.log(`When I send 5 to my function, I get ${func(5)}.`);}experimenter(doubler);experimenter(squarer);

Typeyscript требует, чтобы вы дали Имя к параметру Func , но не имеет значения, что это имя. Я мог назвать это х или Среда или MyFavolitewordword И это не сделало бы никакой разницы. Но даже не думайте о том, чтобы призвать это asshat Отказ Компилятор не позаботится, но как насчет вашего босса? Лучше безопасно, чем извините, это все, что я могу сказать.

В JavaScript все внутри объекта – это свойство – своего рода переменная – и это включает в себя функции. Как следствие, эти два интерфейса означают то же самое:

interface Thing1 {  func: (param: number) => number;}interface Thing2 {  func(param: number): number;}

И так этот код разрешен:

class Thing {  func(x: number) { return x * x * x; }}let t1: Thing1 = new Thing();let t2: Thing2 = t1; 

Вам кажется, что ThereScript требуется : до возвращения типа «нормальной» функции, но это требует = & . GT; Перед возвратом типа функции переменной? Во всяком случае, так это так.

Дженерики и даты и вещи

Даты

Допустим, я пишу функцию, которая обеспечивает значение – это массив, как это:

function asArray(v: any): any[] {  // return v if it is an array, otherwise return [v]  return (Array.isArray(v) ? v : [v]);}

asarmay Функция работает, но она теряет информацию. Например, что, если эта функция вызывает это?

/** Prints one or more dates to the console */function printDates(dates: Date|Date[]) {  for (let date of asArray(dates)) {      // SUPER BUGGY!      var year = date.getYear();      var month = date.getMonth() + 1;      var day = date.getDay();      console.log(`${year}/${month}/${day}`);  }}

Компилятор Tymdercript принимает этот код, но у него есть две ошибки. Код правильно добавлен 1 до месяца, потому что GetMonth () Возвращает 0 за январь и 11 за декабрь. Но код для получения Год и день оба неправильные. С asarmay Возвращает любой [] Однако тип проверки и Intellisense – который мог бы поймать эти ошибки – отключен на Дата Отказ Эти ошибки могли быть удалены, если asarmay Был общий:

function asArray(v: T | T[]): T[] {  return Array.isArray(v) ? v : [v];}

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

В частности, он говорит, что V И возвращаемое значение имеют, ну, подобные типы. Когда вы звоните asarmay Компилятор TypeyctScript находит значение T Это позволяет призыву иметь смысл. Например, если вы звоните asarmay (42) Затем компилятор выбирает T = число Потому что можно использовать 42 в качестве аргумента для asarmay (v: номер | число []): число [] Отказ После выбора T = число Typeyctrctry понимает, что asarmay Возвращает массив номеров.

В PrintDates Мы позвонили asarmay (даты) и компилятор показывает, что T = дата работает лучше всего в этой ситуации. После выбора T = дата Typeyctrctry понимает, что asarmay Возвращает массив Дата Отказ Поэтому переменная Дата имеет тип Дата , а потом он находит первую ошибку: date.getyear не существует! Ну, на самом деле это существует, но он обесценил из-за его поведения – он возвращает количество лет с 1900 – 118 в 2018 году. Вместо этого вы должны позвонить GetLyear Отказ

Само Tymdercript не замечает вторую ошибку. Но, когда вы вводите date.getday . , VS Code сообщит вам в небольшом всплывающем окне, что эта функция «получает день недели, используя местное время». День недели? У вас есть получил Чтобы шутить мне!

Благодаря Generics и VS-коду, мы исправим наш код, чтобы позвонить date.getdate вместо. Это делает не Верните дату без прилагаемого к ней времени, но, скорее, День текущего месяца Отказ В отличие от месяца, день делает не Начните рассчитывать от нуля.

/** Prints one or more dates to the console */function printDates(dates: Date|Date[]) {  for (let date of asArray(dates)) {      var year = date.getFullYear();      var month = date.getMonth() + 1;      var day = date.getDate();      console.log(`${year}/${month}/${day}`);  }}

Одна хорошая вещь о Дата Это то, что они обычно хранятся в UTC – универсальный часовой пояс или GMT. Это означает, что если пользователь меняет часовой пояс на своем компьютере, Дата Объекты в вашей программе продолжают представлять то же самое Укажите во времени , но строка возвращена .tostring () изменения. Обычно это то, что вы хотите, особенно в JavaScript, где у вас может быть код клиента и сервера, работающий в разных часовых поясах.

Универсал

Усовершенствованный пример дженериков появляется в моем Simpletime модуль Отказ В этом случае у меня был График Функция, которая приняла список вариантов форматирования, как это:

export interface TimeFormatOptions {  /** If true, a 24-hour clock is used and AM/PM is hidden */  use24hourTime?: boolean;  /** Whether to include seconds in the output (null causes seconds   *  to be shown only if seconds or milliseconds are nonzero) */  showSeconds?: boolean|null;  ...}
export function timeToString(time: Date|number,                              opt?: TimeFormatOptions): string {  ...}

Экспорт Ключевое слово используется для совместного использования кода в другие исходные файлы. Например, вы можете импортировать График В вашем собственном коде использовано Импорт {разобрать} из «SimPlertime» (после установки с помощью NPM I Shireptime Конечно). Если вы хотите импортировать вещи из другого файла в Та же папка добавить ./ префикс на имя файла, например Импорт * как материал из "./mystuff ' Отказ

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

var primes = new Set([2, 3, 5, 7]);for (var i = 0; i < 10; i++)  console.log(`Is the number ${i} prime? ${primes.has(i)}`);

В типеприктору, хотя Установить имеет тип параметра, Установить < ; T>, означает, что все предметы в наборе имеют Тип T. В этом коде находятся напечатающие устройства что t = номер, так что если вы Напишите PRIMES.ADD («он LLO!») Вы получите ошибку типа. Если вы действуете Uall Вы хотите создать набор, который может удерживать как строки, так и цифры, вы можете сделать это так:

var primes = new Set([2, 3, 5, 7]); 

Вы также можете создать свои собственные общие типы. Например, я создал B + дерево Структура данных называется BTREE V>, который представляет собой коллекцию пар клавишных пар, отсортированных по ключу, что поддерживает быстрое клонирование. У него есть два типа Параме T ers, k (ключ ) и v (значение) и его определение выглядит примерно как это Отказ Примечание. Функциональные тела были опущены, потому что я просто хочу показать вам, как выглядит универсальный класс:

Литералы как типы

Помните, как произошла ошибка, когда вы пишете это?

let z = 26;z = "Zed";

Сообщение об ошибке звучит немного странно:

Type '"Zed"' is not assignable to type 'number'

Почему это говорит о том, что "Zed" это «тип», а не «ценность» или «строка»? Чтобы понять это, необходимо понимать, что Tymdercript имеет возможность лечить значения как типы. "Zed" это строка , конечно, но это больше, чем это – имеет другой тип в то же время более конкретный тип называется "Zed" который представляет ценность "Zed" Отказ Мы можем даже создать переменную с таким типом:

let zed: "Zed" = "Zed";

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

zed = "Zed"; // OKzed = "ZED"; // Error: Type '"ZED"' is not assignable to type '"Zed"'.

По умолчанию мы можем установить Zed к null и неопределенный. К счастью с "Strictnullchecks": правда Опция, мы можем закрыть эту лазейку, чтобы эта переменная никогда не будет ничем, кроме «Zed». Слава Богу за это, это все, что я могу сказать.

Так что же хорошо для этих буквальных типов? Ну, иногда функция позволяет только определенным конкретным строкам. Например, представьте, если у вас есть функция, которая позволяет вам поворот («левый») или Обратитесь («правильно») Но больше ничего. Эта функция может быть объявлена с помощью буквального типа:

function turn(direction: "left"|"right") { … }

Массивы с фиксированной длиной

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

Точно так же [строка, номер] Обозначает массив длины 2 с первым элементом, являющимся строкой, а второй – число. Кроме того, массив имеет свойство Длина: 2 , то есть его Тип это 2 не только Номер Отказ Эти массивы фиксированной длины называются типы кортежей.

Расширенные дженерики

Итак, помните SimPlertime Модуль я говорил? Это также экспортирует Default NameFormat Объект, который удерживает значения по умолчанию для График Варианты форматирования. Я хотел определить специальную функцию, которая позволила бы мне написать такие вещи, как Получить (варианты, «Использование24Гурее») Чтобы получить значение Опции. Нажмите24hourtime Если он существует и Default TimeFormat.use24HourteTime Если это не существует.

На многих языках невозможно написать такую функцию, но в «динамических» языках такой JavaScript. Вот как получить Функция будет выглядеть в JavaScript:

function get(opt, name) {  if (opt === undefined || opt[name] === undefined)    return defaultTimeFormat[name]  return opt[name];}

В JavaScript и Teadycript, вещь. Проверьте можно записать как вещь [«Свойство»] вместо этого и, если свойство не существует, результат это undefined Отказ Но в версии квадратной кронштейны мы можем использовать Переменная так что вопрос “Какая собственность мы используем?” можно ответить кодом, расположенным в другом месте.

Перевод этого в Teadycript возможно с функцией под названием Keyof , но это Очень сложный. Вот перевод:

function get<;K extends keyof TimeFormatOptions>(         opt: TimeFormatOptions|undefined, name: K):          TimeFormatOptions[K]{  if (opt === undefined || opt[name] === undefined)    return defaultTimeFormat[name]  return opt[name];}

Здесь переменная типа К имеет ограничение к этому, K продлевает ключевые слова timeformationstions Отказ Вот как это работает:

  1. Keyof x превращает свойства Х в профсоюзный тип имен свойств. Например, учитывая Книга Интерфейс с более раннего, Keyof Book означает «Название» | «Автор» | «Возраст» Отказ Аналогично Keyof TimeMathatoptions Есть ли какие-либо имена свойств в Портформатопии Отказ
  2. «Расширение» ограничения, Х расширяет y означает, что «X должен быть y или подтип Y». Например X расширяет объект означает, что Х Должен быть какой-то Объект , что означает, что это может быть массив или Дата Или даже функция, все из которых считаются объектами, но это не может быть строка или Номер или логический Отказ Точно так же Х продлевает точку означает, что Х это Точка или Более конкретный Тип, чем Точка , например Point3D Отказ
  3. Что бы …| B Расширяет Keyof Book иметь в виду? Это будет означать, что B это подтип «Название» | «Автор» | «Возраст» Отказ И помните, что мы говорим о Типы Здесь не значения. Струнная буквальная «Название» имеет значение «Название» Но это также имеет тип «Название» , что это другое понятие. Тип обрабатывается системой типового типа, а значение обрабатывается JavaScript. «Название» Тип больше не существует, когда программа работает, но «Название» Значение все еще делает. Теперь B могут быть назначены типы, как «Название» или «Название» | «Возраст» , потому что каждое значение типа «Название» | «Возраст» (или «Название« ) можно назначить для переменной типа Keyof Book Отказ Однако B не может быть строка Потому что некоторые строки не «титул», «автор» или «возраст». Точно так же
  4. К ограничен, чтобы иметь подтип Keyof TimeMathatoptions , например “User24hourtime” Отказ Тип
  5. X [y] Средства «Тип свойства Y x, где y - номер или строковый литерал». Например, Тип Книга [“Автор”] это строка |. undefined Отказ

Положить это все вместе, когда я пишу Получить (варианты, «Использование24Гурее») Компилятор решает, что K = 'use24hourtime " Отказ Поэтому Имя Параметр имеет тип "User24hourtime" и тип возврата – TimeMathatoptions [«Использование24HourTime»] , что означает булевы |. undefined Отказ

Отверстия в системе типа

Поскольку TypeScript построен на вершине JavaScript, он принимает некоторые недостатки в системе своего типа по разным причинам. Ранее мы видели одно из этих недостатков, тот факт, что этот код законно:

class Box {  constructor(public width: number, public height: number) {}  get area() { return this.width*this.height; }}
interface IArea {  area: number; // area is not readonly}
let ia: IArea = new Box(10,100);ia.area = 5; // Accepted by TypeScript, but causes a runtime error

Вот некоторые другие интересные лазейки:

Вы можете назначить полученный класс в базовый класс

А Дата это своего рода Объект Так что естественно вы можете написать:

var d: Object = new Date();

Так что имеет смысл, что мы также можем назначить это D Интерфейс к этому O Интерфейс, верно?

interface D { date: Date }interface O { date: Object }var de: D = { date: new Date() };    // okay...var oh: O = de;                      // makes sense...oh.date = { date: {wait:"what?"} }   // wait, what?

Ну, нет, не совсем, потому что TyplectScript теперь считает de.date это Дата Когда это на самом деле Объект Отказ

Вы можете назначить [A, B] для (A | B) []

Имеет смысл, что массив двух предметов, А сопровождаемый B также является массивом A | B , верно? На самом деле, нет, не совсем:

var array1: [number,string] = [5,"five"];var array2: (number|string)[] = array1;   // makes sense...array2[0] = "string!";                    // wait, what?

Teadycript теперь считает Array1 [0] это Номер Когда это на самом деле строка Отказ Это пример более общей проблемы, которые массивы рассматриваются как ковариант, но они не действительно ковариант, потому что они редактируются.

Массивы? Там будут драконы.

В рекомендуемом Строгий Режим, вы не можете поставить null или undefined В массивах номеров …

var a = [1,2,3];a[3] = undefined; // 'undefined' is not assignable to type 'number'

Так что это означает, что когда мы получаем значение из массива чисел, это число, верно? На самом деле, нет, не совсем:

var array = [1,2,3];var n = array[4];

Teadycript теперь считает N это Номер Когда это на самом деле undefined Отказ

Более очевидная дыра состоит в том, что вы можете выделить размерный массив номеров … без номеров в нем:

var array = new Array(2); // array of two "numbers"var n:number = array[0];

Параметры функции бивариант при переопределении

В отличие от других языков со статическими наборами, Teadercript позволяет переопределять с ковариантными параметрами. Ковариантный параметр означает, что, поскольку класс становится более конкретным (A до B), параметр также получает более конкретный (объект на сегодня):

class A {    method(value: Object) { }}
class B extends A {    method(value: Date) { console.log(value.getFullYear()); }}
var a:A = new B();a.method({}); // Calls B.method, which has a runtime error

Это небезопасно, но странно допускается. Напротив, он (относительно) безопасен для переопределения контравариант Параметры, как это:

class A {    method(value: Date) { }}class B extends A {    method(value: Object) { console.log(value instanceof Date); }}

Ковариантные типы возврата также безопасны:

class A {    method(): Object { return {} }}class B extends A {    method(): Date { return new Date(); }}

Teamprctry по праву отклоняет контравариантные типы возврата:

class A {    method(): Date { return new Date(); }}class B extends A {    // Property 'method' in type 'B' is not assignable to     // the same property in base type 'A'.    //   Type '() => Object' is not assignable to type '() => Date'    //     Type 'Object' is not assignable to type 'Date'    method(): Object { return {} }}

Классы думают, что они интерфейсы (но они не)

Tymdercript позволяет вам относиться к классу, как будто это интерфейс. Например, это законно:

class Class {  content: string = "";}
var stuff: Class = {content:"stuff"};

Вещи не настоящий Класс , но TypectScript думает, что это может вызвать время выполнения Типеррор Если вы используете instanceof class Где-то еще в программе:

function typeTest(x: Class|Date) {  if (x instanceof Class)    console.log("The class's content is " + x.content);  else    console.log("It's a Date in the year " + x.getFullYear());}
typeTest(stuff);

Это не обязательно то, что вы думаете

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

class Time {  constructor(public hours: number, public minutes: number) { }  toDate(day: Date) {    var clone = new Date(day);    clone.setHours(this.hours, this.minutes);    return clone;  }}
// Call toDate() with this=12345Time.prototype.toDate.call(12345, new Date());

ТОЛЬКО TEMPSCRESTS только грех – это то, что он не попытается остановить вас от этого.

Говоря о это одна вещь JavaScript разработчиков должна знать, что Функции стрелки как х => X + 1 работа немного по-разному, чем анонимные функции Li ke Функция (x) {return x +1}.

Стрелка Функции наследуют значение это из внешней функции, в которой они расположены. Нормальный Функции получают новое значение это от абонента. Итак, если F Функция стрелки, f.call (12345, X) не меняется это Так что это как звонить f (x) Отказ Обычно это хорошо, но если вы пишете:

var obj = {x: 5, f: () => Это. Икс }

Вы должны понимать, что obj.f () делает не Возвращение obj.x Отказ

Уроки

Чтобы избежать этих дыр, вам нужно:

  • Не лечить объект В качестве типа «Baser» (например, не лечить d в качестве o ) Если вы не уверены, что тип BASER не будет изменен таким образом, который может нарушить систему типа.
  • Не лечить массив В качестве типа «Baser» (например, не лечить d [] как o [] или [a, b] как (A | b) [] ) Если вы не уверены, что тип Baser не будет изменен таким образом, чтобы он мог нарушить систему типа.
  • Будьте осторожны, чтобы не оставить какие-либо «дыры» с неопределенными значениями в ваших массивах.
  • Будьте осторожны, чтобы не использовать индексы OUT-BASTS MARY.
  • Не Переопределить метод базового класса с ковариантными параметрами.
  • Избегать относиться к классу К Как будто это был интерфейс, если вы не уверены, что код не проверит тип с Instanceof Отказ
  • Избегать Использование .call (...) И будьте осторожны, как вы имеете дело со ссылками на функции.

TypeyctScript на самом деле имел Подробнее дыры В прошлом, которые сейчас подключены.

Jsx.

Реагистрация ввела концепцию кода JSX. Или, может быть, Hyperscript ввел его и отреагировал, скопировал идею вскоре после этого. В любом случае JSX выглядит Как код HTML/XML. Но вы не делаете DOM-элементы, вы делаете обычные объекты JavaScript, которые мы называем «виртуальным домом». Например, }/> На самом деле Средства ract.createelement («IMG», {SRC: Image URL}) в файле .jsx или .tsx.

Если JSX является реагированием, почему я говорю об этом в разделе TypeyctSteSt? Поскольку поддержка JSX встроена в типографский компилятор. Чтобы получить поддержку JSX в любом файле Tearscript, вам просто нужно изменить расширение файла с .ts к .tsx Отказ

JSX можно использовать в тех же местах, что и обычные выражения: вы можете пройти код JSX на функцию …

ReactDOM.render(

I'm JSX code!

, document.body);

Вы можете хранить его в переменной …

let variable = 

I'm JSX code!

;

И вы можете вернуть его из функции …

return 

I'm JSX code!

;

Потому что

Я код JSX

! действительно Просто означает отреагирование .Createlement («H1», NULL, «Я Код jsx!»).

Важно, начинается ли метка JSX с заглавными буквами – она переводится на Typescript (или JavaScript) по-разному Если это так. Например:

  • означает отреагировать .Createelement («div», {"класс": " foo"}), но
  • Средства agep.createelement (Div, {"класс": " foo"}) (без цитата A ROU ND DIV).

Советы по использованию JSX:

  • JSX – это XML-подобное, поэтому все теги должны быть закрыты: напишите R/> нет т. т.
  • JSX поддерживает только строковые атрибуты и выражения JavaScript. При написании числовых атрибутов в Teamscript используйте }/>, быть вызвать м AX = 100 - синтаксис erro R и MAX = «100» - ошибка типа.
  • В RECT/PREACT вы можете использовать массив элементов в любом месте, где ожидается список детей. Например, вместо Вернуться

    Энн Боб

    Cam & L t;/p>, вы можете написать письмо X = [, «BOB», & LT; BR/>]; Возврат

    ann {x} cam

    . Это имеет тот же эффект, потому что React/Preact «Flatts» массивы в дочернем списке.
  • В реакции, Класс Атрибут не поддерживается по какой-то причине. Использовать классное значение вместо.
  • Сам JSX не поддерживает необязательное свойство или детей. Например, предположим, что вы пишете X}> Но вы хотите оми т го реприз Когда x und эфин. Ну, сама JSX не поддерживает ничего подобного. Тем не менее, большинство компонентов TRE в und Эфирное свойство так же, как отсутствующее свойство, поэтому обычно это обычно работает. JSX также не поддерживает необязательные дети, но вы можете получить тот же эффект с пустым массивом: поскольку массивы «рухнуты», реагирующие/PR eact, {[]} имеет t Он же Eff EC t как oo>. {undefined} не имеет этого эффекта (Вы заканчиваются вверх с одним ребенком, равным undefined.)
  • Если у вас есть объект, как obj = {a: 1, b: 2} И вы хотели бы использовать все свойства объекта как свойства компонента, вы можете написать <Компонент {... Obj }/>. Точки всегда вопреки ИРЕД; T {OBJ}/> не допускается.

В верхней части файла @JSX Pragma может контролировать функцию «Фабрика», которая вызывается для перевода элементов JSX. Например, если вы используете /** @jsx h */ Тогда th это tr Таблицы h ('b', n ull, “Это”) Вместо реагирования. Createidelement («B», N Ull, «это»). Некоторые преобразованные приложения используют T H Pragma (H – функция PREACT для создания элементов), но вам не нужно его использовать в Thi S Учебник (C reatelement – это s ynomy для h). Кроме того, в «TSConfig.json» вы можете получить то же самое Эффект с "jsxf actory”: «H» в COM Пилерофтиции.

Смотрите также

Типписная эволюция Объясняет новейшие чертографические функции более подробно. Вы также можете увидеть Расширенные типы в руководстве на 33.

Перед тем, как ты уйдешь…

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