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

Сущность void имеется также в JavaScript и TypeScript. В JS это — оператор. В TS это примитивный тип данных. И там и там void ведёт себя не так, как могли бы ожидать многие из тех, кто сталкивался с void в других языках.
Оператор void в JavaScript
В JavaScript оператор void вычисляет переданное ему выражение. При этом, независимо от того, какое именно выражение вычисляется, void всегда возвращает undefined .
let i = void 2; // i === undefined
Зачем вообще нужен подобный оператор?
Во-первых, надо отметить, что в ранние годы JS-программирования разработчики могли переопределять undefined и записывать в него какое-нибудь своё значение. А вот void всегда возвращает настоящее значение undefined .
Во-вторых — использование оператора void — это интересный способ работы с немедленно вызываемыми функциями:
void function() < console.log('What') >()
И всё это — без загрязнения глобального пространства имён:
void function aRecursion(i) < if(i >0) < console.log(i--) aRecursion(i) >>(3) console.log(typeof aRecursion) // undefined
Так как оператор void всегда возвращает undefined и всегда вычисляет переданное ему выражение, в нашем распоряжении оказывается весьма выразительный способ возвращения из функции без возврата какого-то значения, но с вызовом, например, некоего коллбэка:
// возврат чего-то кроме undefined приведёт к аварийной остановке приложения function middleware(nextCallback) < if(conditionApplies()) < return void nextCallback(); >>
Это приводит нас к самому важному способу использования void . Данный оператор представляет собой нечто вроде «поста охраны» приложения. Если некая функция всегда должна возвращать undefined — обеспечить это можно, воспользовавшись оператором void .
button.onclick = () => void doSomething();
Тип данных void в TypeScript
Тип void в TypeScript можно назвать чем-то вроде противоположности типа any . Функции в JavaScript всегда что-то возвращают. Это может быть либо некое заданное программистом значение, либо undefined :
function iHaveNoReturnValue(i) < console.log(i) >// возвращает undefined
Так как JavaScript функции, из которых явным образом ничего не возвращается, всегда возвращают undefined , void в TypeScript является подходящим типом, сообщающим разработчикам о том, что функция возвращает undefined :
declare function iHaveNoReturnValue(i: number): void
Сущность void в виде типа можно ещё использовать для параметров и для любых других объявлений переменных. Единственное значение, которое всегда можно передать void-параметру — это undefined .
declare function iTakeNoParameters(x: void): void iTakeNoParameters() // ОК iTakeNoParameters(undefined) // ОК iTakeNoParameters(void 2) // ОК
В результате оказывается, что в TS типы void и undefined — это почти одно и то же. Но между ними есть одно маленькое различие, которое, на самом деле, чрезвычайно важно. Возвращаемый тип void может быть заменён на другие типы, что позволяет реализовывать продвинутые паттерны работы с коллбэками.
function doSomething(callback: () => void) < let c = callback() //здесь callback всегда возвращает undefined //тип c - тоже undefined >// эта функция возвращает число function aNumberCallback(): number < return 2; >// работает; обеспечивается типобезопасность в doSometing doSomething(aNumberCallback)
Разработчики ожидают от подобных конструкций, часто используемых в JS-приложениях, именно такого поведения. Вот материал на эту тему.
Если вы хотите, чтобы функция принимала бы лишь функции, которые возвращают undefined — вы можете соответствующим образом изменить сигнатуру метода:
// было // function doSomething(callback: () => void) < // стало function doSomething(callback: () =>undefined) < /* . */ >function aNumberCallback(): number < return 2; >// Ошибка - типы не совпадают doSomething(aNumberCallback)
Итоги
Оператор void в JavaScript и тип данных void в TypeScript — сущности довольно простые и понятные. Круг ситуаций, в которых они применимы, ограничен. Однако надо отметить, что программист, который их использует, скорее всего, не столкнётся при работе с ними с какими-то проблемами.
Уважаемые читатели! Пользуетесь ли вы void в JS и TS?
Примитивные типы Null, Undefined, Void, Never, Unknown¶
Настало время рассмотреть следующую порцию типов, некоторые из которых являются уникальными для TypeScript.
Важно¶
Прежде чем приступить к знакомству с такими типами, как Null , Undefined , Void , Never и Unknown , стоит обговорить одну очень важную деталь. Дело в том, что все перечисленные типы можно указывать в качестве типа всем конструкциям, которые это позволяют. То есть типом данных null можно аннотировать даже переменную ( let identifier: null ). Данная книга будет изобиловать подобными примерами, так как эта возможность облегчает демонстрацию совместимости типов. Но при этом стоит понимать, что проделывать подобное в реальном коде противопоказано.
Null примитивный null тип¶
Примитивный тип Null служит обозначением “ничего”.
Тип Null указывается с помощью ключевого слова null (не путать с единственным литеральным значением null типа Null , которое присваивается в качестве значения).
let identifier: null = null; // null, указанный после оператора двоеточия, это имеющийся только в TypeScript псевдоним (alias) для глобального типа Null. В то время как null, указанный после оператора присваивания, это единственное значение типа Null.
Тип Null является подтипом всех типов, за исключением типа Undefined , поэтому его единственное значение null совместимо со всеми остальными типами данных.
1 2 3 4 5 6 7
class TypeSystem static any: any = null; // Ok static number: number = null; // Ok static string: string = null; // Ok static boolean: boolean = null; // Ok static null: null = null; // Ok >
В то время как тип null совместим со всеми типами, помимо него самого, с ним самим совместим лишь тип undefined и any .
1 2 3 4 5
TypeSystem.null = TypeSystem.any; // Ok TypeSystem.null = TypeSystem.number; // Error TypeSystem.null = TypeSystem.string; // Error TypeSystem.null = TypeSystem.boolean; // Error TypeSystem.null = TypeSystem.null; // Ok
Тогда, когда тип данных указывается не явно, а в качестве значения используется значение null , вывод типов определяет принадлежность к типу any .
let identifier = null; // identifier: any
Создатели TypeScript во избежание ошибок, возникающих при операциях, в которых вместо ожидаемого значения возможно значение null , рекомендуют вести разработку с активным флагом —strictNullChecks . При активном флаге —strictNullChecks тип null является подтипом только одного типа any . Это в свою очередь означает, что значение null может быть совместимо только с типами any и null .
1 2 3 4 5 6 7 8 9 10 11 12 13
class TypeSystem static any: any = null; // Ok static number: number = null; // Error static string: string = null; // Error static boolean: boolean = null; // Error static null: null = null; // Ok > TypeSystem.null = TypeSystem.any; // Ok TypeSystem.null = TypeSystem.number; // Error TypeSystem.null = TypeSystem.string; // Error TypeSystem.null = TypeSystem.boolean; // Error TypeSystem.null = TypeSystem.undefined; // Ok
При активном флаге —strictNullChecks , при условии, что в качестве значения выступает значение null , вывод типов определяет принадлежность к типу null .
let identifier = null; // identifier: null
Тип null идентичен по своей работе с одноимённым типом из JavaScript.
Undefined примитивный неопределенный тип¶
Примитивный тип undefined указывает на то, что значение не определено. Тип данных undefined указывается с помощью ключевого слова undefined (не путать со свойством глобального объекта undefined , которое представляет единственное значение типа Undefined ).
let identifier: undefined = undefined; // undefined, указанный после оператора двоеточия, это имеющийся только в TypeScript псевдоним (alias) для глобального типа Undefined. В то время как undefined, указанный после оператора присваивания, это единственное значение типа Undefined.
Во время выполнения объявленные, но не инициализированные переменные, поля и свойства класса, а также параметры имеют значение undefined . Также значение undefined является результатом вызова методов или функций, которые не возвращают значения.
Тип undefined является подтипом всех типов, что делает его совместимым со всеми остальными типами.
1 2 3 4 5 6 7 8
class TypeSystem static any: any = undefined; // Ok static number: number = undefined; // Ok static string: string = undefined; // Ok static boolean: boolean = undefined; // Ok static null: null = undefined; // Ok static undefined: undefined = undefined; // Ok >
Может возникнуть вопрос, почему тип null , который не имеет непосредственного отношения к типу undefined , совместим с ним? На данный момент, этот вопрос так и остается неразгаданным.
В то время как тип данных undefined совместим со всеми типами, помимо него самого, с ним совместимы лишь null и any .
1 2 3 4 5
TypeSystem.undefined = TypeSystem.any; // Ok TypeSystem.undefined = TypeSystem.number; // Error TypeSystem.undefined = TypeSystem.string; // Error TypeSystem.undefined = TypeSystem.boolean; // Error TypeSystem.undefined = TypeSystem.null; // Ok
Тогда, когда тип данных undefined указывается не явно, компилятор устанавливает тип any .
let identifier = undefined; // identifier: any
При активном флаге —strictNullChecks , тип undefined является подтипом только одного типа any . Поэтому ему в качестве значения, помимо самого себя, можно присвоить только тип any .
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class TypeSystem static any: any = undefined; // Ok static number: number = undefined; // Error static string: string = undefined; // Error static boolean: boolean = undefined; // Error static null: null = undefined; // Error static undefined: undefined = undefined; // Ok > TypeSystem.undefined = TypeSystem.any; // Ok TypeSystem.undefined = TypeSystem.number; // Error TypeSystem.undefined = TypeSystem.string; // Error TypeSystem.undefined = TypeSystem.boolean; // Error TypeSystem.undefined = TypeSystem.null; // Error
При активном флаге —strictNullChecks , при условии, что в качестве значения выступает значение undefined , вывод типов определяет принадлежность к типу undefined .
let identifier = undefined; // identifier: undefined
Тип undefined идентичен по своей работе с одноимённым типом из JavaScript.
Void отсутствие конкретного типа¶
Тип данных Void можно назвать полной противоположностью типа any , так как этот тип означает отсутствие конкретного типа. Основное предназначение типа Void — явно указывать на то, что у функции или метода отсутствует возвращаемое значение.
Тип данных Void указывается с помощью ключевого слова void (не путать с одноимённым оператором из JavaScript) и, в отличие от таких типов, как null и undefined , не имеет никаких значений.
Тип void является подтипом any и супертипом для null и undefined .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
function action(): void <> class TypeSystem static any: any = action(); // Ok static number: number = action(); // Error static string: string = action(); // Error static boolean: boolean = action(); // Error static null: null = action(); // Error static undefined: undefined = action(); // Error static void: void = action(); // Ok > TypeSystem.void = TypeSystem.any; // Ok TypeSystem.void = TypeSystem.number; // Error TypeSystem.void = TypeSystem.string; // Error TypeSystem.void = TypeSystem.boolean; // Error TypeSystem.void = TypeSystem.null; // Ok TypeSystem.void = TypeSystem.undefined; // Ok TypeSystem.void = TypeSystem.void; // Ok
Однако с активным флагом —strictNullChecks , тип данных void совместим лишь с any и undefined .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
function action(): void <> class TypeSystem static any: any = action(); // Ok static number: number = action(); // Error static string: string = action(); // Error static boolean: boolean = action(); // Error static null: null = action(); // Error static undefined: undefined = action(); // Error static void: void = action(); // Ok > TypeSystem.void = TypeSystem.any; // Ok TypeSystem.void = TypeSystem.number; // Error TypeSystem.void = TypeSystem.string; // Error TypeSystem.void = TypeSystem.boolean; // Error TypeSystem.void = TypeSystem.null; // Error TypeSystem.void = TypeSystem.undefined; // Ok TypeSystem.void = TypeSystem.void; // Ok
Кому-то может показаться, что примеры чересчур излишни, или что примеры, в которых результат вызова функции, не имеющей возвращаемого значения, присваивается полям с различными типами, не имеет никакого отношения к реальности. Да, это так. Но целью данных примеров является научить думать как компилятор TypeScript.
Когда функции в качестве возвращаемого типа указан тип void , может показаться, что возвращая различные значения с помощью оператора return , компилятор выбрасывает ошибки из-за понимания, что функция помечена как ничего не возвращающая. Но это не так. Ошибка возникает по причине несовместимости типов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
function a(): void let result: number = 5; return result; // Error > function b(): void let result: string = '5'; return result; // Error > function c(): void let result: any = 5; return result; // Ok >
Нельзя не упомянуть, что для функций и методов, которые ничего не возвращают и у которых отсутствует аннотация типа возвращаемого значения, вывод типов определяет принадлежность к типу void .
1 2 3
function action() // function action(): void >
В отличие от null и undefined , тип void не имеет ни одного значения, которое могло бы явно продемонстрировать присвоение. Однако компилятор понимает, что имеет дело с типом void при вызове функции или метода, которые не возвращают значение. Это становится ещё нагляднее, когда вывод типов устанавливает тип, полученный при вызове функции или метода, которые ничего не возвращают.
1 2 3
function action(): void <> let identifier = action(); // identifier: void
Тип void является уникальным для TypeScript. В JavaScript подобного типа не существует.
Never примитивный тип¶
Примитивный типа данных Never служит для указания того, что какие-либо операции никогда не будут выполнены.
Never обозначается ключевым словом never и так же, как и void , не имеет явных значений.
Тип данных never является подтипом всех типов, что делает его совместимым со всеми остальными типами.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
function action(): never throw new Error(); > class TypeSystem static any: any = action(); // Ok static number: number = action(); // Ok static string: string = action(); // Ok static boolean: boolean = action(); // Ok static null: null = action(); // Ok static undefined: undefined = action(); // Ok static void: void = action(); // Ok static never: never = action(); // Ok > TypeSystem.never = TypeSystem.any; // Error TypeSystem.never = TypeSystem.number; // Error TypeSystem.never = TypeSystem.string; // Error TypeSystem.never = TypeSystem.boolean; // Error TypeSystem.never = TypeSystem.null; // Error TypeSystem.never = TypeSystem.undefined; // Error TypeSystem.never = TypeSystem.void; // Error TypeSystem.never = TypeSystem.never; // Ok
Так как типу never нельзя присвоить значение, отличное от самого типа never , единственным местом, в котором его может использовать разработчик, является аннотация возвращаемого из функции или метода значения, с одной оговоркой. Тип never можно указать только той функции, из которой программа действительно никогда не сможет выйти.
Такой сценарий может выражаться в виде функции, вызов которой приведет к однозначному исключению или тело функции будет включать бесконечный цикл.
1 2 3 4 5 6 7
function error(message: string): never throw new Error(message); > function loop(): never while (true) <> >
Вывод типов определит принадлежность возвращаемого функцией значения к типу never , только если он указан в аннотации возвращаемого типа явно.
1 2 3 4 5 6 7 8 9 10 11
function error(message: string): never throw new Error(message); > function action() // function action(): never return error('All very, very bad.'); > let identifier = error(); // let identifier: never let identifier = action(); // let identifier: never
Стоит заметить, что без явного указания типа never вывод типов определит принадлежность возвращаемого значения к типу void .
1 2 3 4 5 6 7 8 9
function error(message: string) // function error(): void throw new Error(message); > function loop() // function loop(): void while (true) <> >
Тип never является уникальным для TypeScript. В JavaScript подобного типа не существует.
Unknown¶
Тип Unknown является типобезопасным аналогом типа any и представлен в виде литерала unknown . Все типы совместимы с типом unknown , в то время как сам тип unknown совместим только с самим собой и типом any .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
class TypeSystem static unknown: unknown; static any: any = TypeSystem.unknown; // Ok static number: number = TypeSystem.unknown; // Error static string: string = TypeSystem.unknown; // Error static boolean: boolean = TypeSystem.unknown; // Error static null: null = TypeSystem.unknown; // Error static undefined: undefined = TypeSystem.unknown; // Error static void: void = TypeSystem.unknown; // Error static never: never = TypeSystem.unknown; // Error > TypeSystem.unknown = TypeSystem.any; // Ok TypeSystem.unknown = TypeSystem.number; // Ok TypeSystem.unknown = TypeSystem.string; // Ok TypeSystem.unknown = TypeSystem.boolean; // Ok TypeSystem.unknown = TypeSystem.null; // Ok TypeSystem.unknown = TypeSystem.undefined; // Ok TypeSystem.unknown = TypeSystem.void; // Ok TypeSystem.unknown = TypeSystem.unknown; // Ok
Кроме того, над типом unknown запрещено выполнение каких-либо операций.
1 2 3 4 5 6 7 8 9
let v0: any; v0.a = 5; // Ok v0.a = ''; // Ok v0(); // Ok let v1: unknown = v0; // Ok v1.a = 5; // Error v1.a = ''; // Error v1(); // Error
Если тип unknown составляет тип пересечение ( intersection ), то он будет перекрыт всеми типами.
1 2 3 4 5 6 7 8 9 10
type T0 = any & unknown; // type T0 = any type T1 = number & unknown; // type T1 = number type T2 = string & unknown; // type T2 = string type T3 = boolean & unknown; // type T3 = boolean type T4 = null & unknown; // type T4 = null type T5 = undefined & unknown; // type T5 = undefined type T6 = void & unknown; // type T6 = void type T7 = never & unknown; // type T7 = never type T8T> = T & unknown; // type T8 = T type T9 = unknown & unknown; // type T9 = unknown
Если тип unknown составляет тип объединение ( union ), то он перекроет все типы, за исключением типа any .
1 2 3 4 5 6 7 8 9 10
type T0 = any | unknown; // type T0 = any type T1 = number | unknown; // type T1 = unknown type T2 = string | unknown; // type T2 = unknown type T3 = boolean | unknown; // type T3 = unknown type T4 = null | unknown; // type T4 = unknown type T5 = undefined | unknown; // type T5 = unknown type T6 = void | unknown; // type T6 = unknown type T7 = never | unknown; // type T7 = unknown type T8T> = T | unknown; // type T8 = unknown type T9 = unknown | unknown; // type T9 = unknown
Помимо этого, запрос ключей ( keyof ) для типа unknown возвращает тип never .
1 2 3
type T0 = keyof number; // type T0 = "toString" | "toFixed" | "toExponential" | "toPrecision" | "valueOf" | "toLocaleString" type T1 = keyof any; // type T1 = string | number | symbol type T2 = keyof unknown; // type T2 = never
Тип unknown позволяется использовать только в операциях равенства === , == , !== и != и в операциях с логическими операторами && , || и ! .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
let v0: unknown = 5; let v1 = 5 === v0; // Ok let v2 = 5 !== v0; // Ok let v3 = 5 > v0; // Error let v4 = 5 v0; // Error let v5 = 5 >= v0; // Error let v6 = 5 v0; // Error let v7 = 5 - v0; // Error let v8 = 5 * v0; // Error let v9 = 5 / v0; // Error let v10 = ++v0; // Error let v11 = --v0; // Error let v12 = v0++; // Error let v13 = v0--; // Error let v14 = 5 && v0; // Ok, let v14: unknown let v15 = 5 || v0; // Ok, let v15: number let v16 = v0 || 5; // Ok, let v16: unknown let v17 = !v0; // Ok, let v17: boolean
Также стоит упомянуть, что функция, у которой возвращаемый тип принадлежит к типу unknown , может не возвращать значение явно.
1 2 3 4 5 6 7 8 9
function f0(): unknown return; // Ok > function f1(): number return; // Error > let v = f0(); // Ok, let v: unknown
При активной опции —strictPropertyInitialization принадлежащие к типу unknown поля не нуждаются в инициализации.
1 2 3 4 5
class T f0: unknown; // Ok f1: number; // Error f2: number = 5; // Ok >
Если в определении типа данных участвует сопоставленный тип ( Mapped Type ), которому в качестве аргумента типа передается тип unknown , то такой сопоставленный тип будет выведен как объектный тип <> . Поскольку сопоставленные типы ( Mapped Types ), псевдонимы типов ( types ), а также обобщения ( Generics<> ) будут рассмотрены позднее, то стоит просто помнить об этом факте и повторно прочесть написанное при необходимости.
1 2 3 4 5 6 7
type MappedTypeT> = [K in keyof T]: T; >; type T0 = MappedTypenumber>; // type T0 = number type T1 = MappedTypeany>; // type T1 = type T2 = MappedTypeunknown>; // type T2 = <>
Типы данных в TypeScript
TypeScript добавляет дополнительные типы данных в JavaScript. Типы данных используются для добавления статических ограничений на программные элементы, такие как функции, переменные и свойства. Это позволяет компилятору и средствам разработки осуществлять более тщательную проверку и поддержку в процессе разработки. Система типов времени компиляции TypeScript моделирует динамическую систему типов времени выполнения JavaScript, позволяя программистам точно выражать взаимодействия типов. Анализ типов в TypeScript осуществляется только во время компиляции и не добавляет никаких задержек во время выполнения готовой программы.
Все типы в TypeScript являются подтипами главного типа, которым является тип Any. Данный тип обозначается ключевым словом any. Тип Any — единственный, который может представлять любое значение JavaScript без всяких ограничений. Все остальные типы накладывают определенные ограничения на свои значения.
Примитивными типами являются Number, String, Symbol, Void, Null, Undefined и также типы-перечисления (enums), определяемые пользователем.
Тип Any
Тип Any используется когда мы не знаем какой тип должна иметь та или иная переменная. Эта переменная может быть получена из некоего динамического содержимого, как например, если бы использовалась некая сторонняя библиотека. В таких случаях нужно отказаться от проверки типов и позволить таким переменным проходить проверку во время компиляции. Для того, чтобы это сделать, нужно указать переменной тип Any с помощью ключевого слова any.
let someVar: any = 4;
someVar= "потом может стать строкой";
someVar= false; // или boolean
Стоит отметить, что если объявить переменную и не указывать ее тип, то будет считаться, что она имеет тип Any.
let withoutTypeVar; // на самом деле переменная имеет тип Any
Рекомендуется всегда явно указывать тип там, где это возможно во избежание ошибок. Но не стоит везде использовать тип Any, т.к. в этом случае нивелируются преимущества, которые дает TypeScript при использовании конкретных типов. Также повсеместное использование данного типа может говорить о плохо продуманном коде и привести к нежелательным ошибкам в будущем.
Тип Any является средством, которое позволяет работать с существующими JavaScript библиотеками и не приводить к ошибкам компиляции.
let notSure: any = 4;
notSure.ifItExists(); // OK, может существовать во время выполнения
notSure.toFixed(); // OK, ошибки компиляции не будет
Может показаться, что тип Object (предоставляет интерфейс для доступа к общим для всех объектов JavaScript методам) может выполнять такую же роль. Однако в данном случае получится только присвоить значение переменной этого типа. Вызвать метод, который может и существует на самом деле не получится
let someObj: Object = 4;
someObj.toFixed(); // Ошибка
Тип Any может прийти на помощь также, если вам известна только часть типа. Например, вам известно, что переменная является массивом, но тип элемента массива неизвестен или элементы могут иметь разный тип. В этом случае можно поступить следующим образом:
let arr: any[] = [1, true, "some string", . ];arr[1] = "another string"; // OK
Примитивные типы
Тип Number
Как и в JavaScript, все числа в TypeScript являются числами с плавающей точкой. Для указания данного типа переменной используется ключевое слово number. Все переменные этого типа также реализуют глобальный интерфейс Number.
let x: number; // Явное указание типа
let y = 0; // Тоже, что и y: number = 0
let z = 123.456; // Тоже, что и z: number = 123.456
let s = z.toFixed(2); // Свойство интерфейса Number
В дополнение к десятичной и шестнадцатеричной форме записи чисел ,TypeScript поддерживает также записи чисел в двоичной и восьмеричной системе, которые появились в стандарте ECMAScript 2015:
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
Тип Boolean
Тип Boolean совпадает с одноименным типом JavaScript и представляет собой логическое значение: истина (true) или ложь (false).
Объявляется данный тип с помощью ключевого слова boolean.
var logical: boolean = false;
var checked = true; // Тоже, что и var checked: boolean = true;
В TypeScript все переменные этого типа реализуют также глобальный интерфейс ‘Boolean’.
Тип String
Тип String соответствует аналогичному в JavaScript и представляет собой последовательность символов в кодировке Unicode UTF-16. Как и в JavaScript, значение строки должно быть окружено либо одинарными, либо двойными кавычками.
var s: string = "some string";
var empty = "";
var another = 'another string';
var c = another.charAt(2); // Свойство интерфейса 'String'
Все переменные данного типа реализуют глобальный интерфейс ‘String’.
Для создания строк также можно пользоваться шаблонами строк.Для этого содержимое строки заключаться в обратные кавычки (`), а выражения должны выглядеть как $ .
let name: string = `Сергей`;
let age: number = 33;
let sentence: string = `Hello, my name is $. I’ll be $ < age + 1 >years old next month.`;
Это будет эквивалентно:
let sentence: string = "Hello, my name is "+ name+ ".\n\n" + "I’ll be "+ (age + 1) + "years old next month.";
Тип Void
Можно сказать, что тип Void является противоположностью типу Any. Этот тип означает отсутствие какого-либо типа. Обычно используется для указания того, что функция не возвращает никакого значения.
function someFunction(): void alert("message");
>
Тип Void является подтипом типа Any, и супертипом для типов Null и Undefined. В тоже время тип Void не зависит от всех остальных типов.
Объявлять переменную с данным типом можно, но это не имеет никакого смысла, т.к. в данном случае такой переменной можно присвоить только значение null или undefined.
let v1: void = null;
let v2: void = undefined;
Типы Null и Undefined
Типы Null и Undefined соответствуют одноименным типам в JavaScript. Данные типы являются подтипами для всех остальных типов по умолчанию.
let n: number = null; // Примитивные типы могут быть null
let m: number = undefined; // Примитивные типы могут быть undefined
let x = null; // тоже самое, что и x: any = null
let y = undefined; // тоже самое, что и y: any = undefined
let e: Null; // Ошибка
let r: Undefined; //Ошибка
Если объявить переменной тип null или undefined, то такой переменной можно будет присвоить только значение null или undefined соответственно, что не имеет никакого практического применения.
let n: null = null; // Только это значение можно присвоить
n = 1; // Ошибка!
let m: undefined = undefined;
m = "some string"; //Ошибка!
Стоит отметить, что если использовать директиву компилятора —strictNullChecks , null и undefined могут быть присвоены только переменной типа void и переменным с типами null или undefined соответственно. Это помогает избежать множества ошибок. В таком случае, если переменной нужно присвоить значение с типом string или null или undefined , можно использовать тип объединение string | null | undefined .
Тип Array
В TypeScript, также как и в JavaScript, можно работать с массивами значений. Для создания массива необходимо к указанному типу переменной добавить [].
var arr: number[] = [1, 2, 3];
var otherArr: any[] = [1, true, "string"];
Созданная переменная также реализует обобщенный интерфейс Array , где Т — тип элементов массива. Свойство length данного интерфейса возвращает количество элементов массива.
interface Array <
length: number; // длина массива
[x: number]: T; // сигнатура для доступа к элементу массива по его индексу
// . остальные методы
>
Соответственно, создавать массивы также можно следующим образом:
var list: Array = [1, 2, 3];
list[1] = 4; // [1, 4, 3]
var length = list.length; // 3
Тип Tuple
Тип Tuple или кортеж представляет собой массив JavaScript, каждому из элементов которого можно указать свой тип. Кортеж
[T1, T2, . Tn]
можно представить как объект с численно именованными свойствами
0: T1,
1: T2,
.
n: Tn
>
let tuple: [string, number];tuple = ["some", 10]; // Правильно
tuple = [10, "some"]; // Неверно! Типы не совпадаютconsole.log(tuple[0]); // "some"
console.log(tuple[1]); // 10
Как и обычному массиву, кортежу можно присвоить значение, которое выходит за пределы определенных типов, например:
tuple[200] = "some string"; // OK
tuple[300] = 1; // OK
tuple[400] = true; // Ошибка!
В этом случае тип элемента должен быть string | number.
Можно создавать именованные кортежи путем объявления интерфейса, унаследованного от Array и введя численно именованные свойства.
interface KeyValuePair extends Array let x: KeyValuePair = [10, “ten”];
Тип Enum
Полезным добавлением к набору типов данных JavaScript является тип Enum (перечисление). Как и языке C#, enum — это способ указать более привычные имена набору числовых значений.
enum Color ;
let c: Color = Color.Green;
По умолчанию у перечислений нумерация начинается с нуля. Но можно поменять это вручную установкой значения например для одного из значений перечисления.
enum Color ; // нумерация начинается с 1
let c: Color = Color.Green;
Или можно для каждого значения назначить свое значение
enum Color ;
let c: Color = Color.Green;
Для получения имени по числовому значению, необходимо
console.log(Color[4]); // выведет в консоли Blue
Тип Never
Тип never представляет тип, значение которого никогда не наступает. Например, never является типом, который возвращает функция, которая всегда бросает исключения или выход из которой никогда не происходит (например бесконечный цикл). Переменные также могут иметь данный тип например для того, чтобы никогда не принимать значение true.
Тип never является подтипом любого типа. Переменная типа never может быть присвоена переменной любого другого типа. С другой стороны, нет такого типа, который будет являться подтипом данного типа, также как и переменной данного типа ничего нельзя присвоить кроме переменной такого же типа (never).
function error(message: string): never throw new Error(message);
>// Выведенным типом fail() будет never
function fail() return error("Something failed");
>// нет выхода из этой функции
function infiniteLoop(): never while (true) >
>
Тип Symbol
Тип Symbol является примитивным и соответствует одноименному типу в языке JavaScript. Данный тип предоставляет уникальные идентификаторы, которые могут быть использованы как ключи для свойств объекта.
Значения, имеющие тип Symbol реализуют глобальный объект ‘Symbol’, который имеет набор методов и свойств, которые могут быть вызваны как функции.
var secretKey = Symbol();
var obj = <>; obj[secretKey] = “secret message”; // Символ как свойство
obj[Symbol.toStringTag] = “test”;
Приведение типов
Иногда может оказаться так, что вы знаете немного больше о значении некоторой переменной, чем определено в TypeScript. Обычно это случается когда вы знаете, что тип некоторой переменной может быть более конкретным или определенным, чем текущий.
Приведение типов — это способ сказать компилятору “Доверься мне, я знаю, что я делаю”. Приведение типов в TypeScript похоже на приведение типов в других языках программирования, но не требует никаких специальных проверок или реструктуризации данных. Также этот процесс не оказывает никакого воздействия на скомпилированную программу и используется только компилятором.
Существует две формы приведения типов. Первый — синтаксис с использованием угловых скобок (<>):
let someValue: any = “this is a string”; let strLength: number = (string>someValue).length;
Второй — as-синтаксис:
let someValue: any = “this is a string”; let strLength: number = (someValue as string).length;
Два приведенных примера полностью аналогичны. Использовать один или другой — по большому счету это выбор предпочтений; однако, когда TypeScript используется совместно с JSX, допускаются только приведение типов через as-синтаксис.
Немного о let
Ключевое слово let является новым в JavaScript. Переменная, объявленная с помощью let будет видна только в текущей (локальной) области видимости. Это позволяет избегать множество проблем в JavaScript. Поэтому рекомендуется пользоваться let вместо var везде, где это возможно.
Тип Void — Основы Typescript
В этом уроке мы рассмотрим тип void . Он указывается как возврат для функций, которые ничего не возвращают.
Использование типа Void
void автоматически выводится, когда внутри функции нет инструкции return или она пустая:
function noop() // внутри пусто >
В JavaScript подобные функции возвращают undefined , но в TypeScript void и undefined — это разные вещи. Они различаются по контекстной типизации. А происходит это из-за особенностей работы самого JavaScript. Самый яркий пример — метод forEach() .
Метод forEach() не использует данные, возвращаемые переданным колбеком, который вызывается внутри. Возможно, логично было бы определить возврат как undefined , но посмотрим на пример:
const numbers = [1, 2, 3]; const result = []; numbers.forEach((n) => result.push(n));
Метод push() возвращает новую длину массива. Если бы forEach() требовал от колбека возврат undefined , то такой код привел бы к ошибке компиляции. Его пришлось бы переписать, например, так:
// Теперь колбек ничего не возвращает, // соответственно, результат вызова undefined numbers.forEach((n) => result.push(n); >);
Чтобы не создавать такой код, и был введен void . Он позволяет возвращать любые данные, но делает так, что их использование бессмысленно.
type VoidFunc = () => void; // Тип функции определяется через контекст // присваивания ее переменной с типом VoidFunc const func: VoidFunc = () => true; const trueResult = func(); // true
Существует единственная ситуация, когда указание void явно запрещает возврат из функции. Это определение функции вне контекста использования, когда ее тип указывается явно:
function foo(): void return true; // Error! > const bar = function(): void return true; // Error! >;
Еще void является оператором JavaScript, поэтому важно не запутаться с ним. Он вычисляет выражение, которое следует за ним и возвращает undefined :
void 10 === undefined // true
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях: