Typescript Flashcards

You may prefer our related Brainscape-certified flashcards:
1
Q

TypeScript преимущества

A
  • Нахождение некоторых видов ошибок еще до запуска кода. В программировании языки делятся на две большие группы: динамически типизированные и статически типизированные. JavaScript относится к первой группе. У таких языков есть интерпретатор, программа, которая выполняет код построчно без предварительного анализа. Статически типизированные, к которым относится TypeScript, языки работают по-другому. Перед тем как запустить код этих языков на выполнение, его нужно скомпилировать. Во время компиляции проверяется, что программа типобезопасна, то есть она не содержит ошибок подобных примеру выше. Если компилятор нашел не соответствие типов, то он останавливает компиляцию и выводит предупреждения о том, где типы не сходятся.
  • Более простой рефакторинг кода
  • Полную поддержку возможностей редактора: автодополнения, навигации по коду и т.п.
  • TypeScript обратно совместим с JavaScript. Любой код, написанный на JS будет выполнен. Также можно писать смешанный код и он будет валиден.
  • Реализует многие принципы объектно-ориентированного программирования: модификаторы доступа, наследование, инкапсуляцию и полиморфизм. Есть система для работы с модулями, классами. Даже есть возможность создавать абстрактные классы.

Минусы:
Наличие дополнительных файлов (*.ts, *.d.ts, *.map), что неудобно для небольших проектов.
Для некоторых браузеров необходима дополнительная настройка консоли для отладки TypeScript.
TypeScript — язык с неявной статической типизацией: тип может быть описан как any, что отключит приведение к этому типу переменной.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

TypeScript: Null и Undefined

A

В TypeScript null и undefined не просто значения, а два типа, состоящие из одного значения.
В TypeScript c правильной (strict) конфигурацией проверка на null встроена и статический анализатор скажет вам о возможной проблеме. Чтобы ее решить, также требуется написать соответствующее условие или использовать оператор ?, что позволяет избежать ошибок во время исполнения кода

function foo(value?: string | null) { if (value !== null && value !== undefined) { const upperValue = value.toUpperCase(); // ^? (parameter) value: string } // остальная логика }

Это стало возможным как раз благодаря выделению значений null и undefined в отдельные типы, а благодаря Narrowing и Union Types не пришлось изобретать дополнительный механизм. И все решение укладывается в концепцию “типы как множества”. Благодаря каждой проверке мы отсекаем не подходящее нам множество значений и получаем безопасный вызов метода. Такие проверки также называются отсечением типов (Differentiating Types) и Type Guards.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

TypeScript: Rest и Spread

A

Rest-оператор позволяет создавать функции с переменным числом параметров, сворачивая их в массив. В этом смысле rest-оператор в TypeScript ничем не отличается от rest-оператора в JavaScript.

function max(...numbers: number[]) { return Math.max(...numbers); }

Spread-оператор в функциях это как rest-оператор наоборот. Он позволяет раскладывать массив на отдельные параметры:
const numbers = [1, 2, 3]; Math.max(...numbers);

Сложность:
Если функция принимает на вход любое количество аргументов, как в примере выше, то такой код работает без проблем, но если функция принимает на вход определенное число аргументов, то TypeScript выдаст ошибку компиляции:
function sum(a: number, b: number) { return a + b; } const args = [1, 2]; sum(...args);

Есть разные способы обойти это ограничение, но в данном случае проще всего использовать Type Assertion. Это указание компилятору того, что мы точно знаем о коде.
const args = [1, 2] as const;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

TypeScript: Аннотации типов (type annotations)

A

В случае составных типов, например если мы хотим использовать объединение или описание объекта добавляются скобки: (Type)[]:
const users: ({ name: string })[] = []; const users: (string | null)[] = [];

TypeScript дает еще один синтаксис, который описывается так: Array<Type>. Он универсальный и с его помощью можно описать любой массив. Форма Array нужна в первую очередь для дженериков.
`const users: Array<string> = [];
const users: Array<number> = [];
const users: Array<User> = [];
const users: Array<{ name: string }> = [];
const users: Array<string | null> = [];`</User></number></string></Type>

Если определить пустой массив без указания типа, то его типом автоматически станет any[]. В такой массив можно добавить любые данные, включая вложенные массивы. Код с any будет работать всегда, но он выключает проверку типов. Чтобы этого не происходило, нужно всегда явно типизировать пустой массив.
const items = []; items.push(1); items.push('wow'); items.push(['code-basics', 'hexlet']);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

TypeScript: Анонимные функции

A

Т.к. анонимные и стрелочные функции почти всегда используются в том же месте, где и определяются, TypeScript может вывести типы их параметров. Для определения таких функций указание типов опускают. Этот процесс называется контекстная типизация (contextual typing), так как контекст определения функции, позволяет вывести типы входных параметров.
const fruits = [‘banana’, ‘mango’, ‘apple’];
const upperFruits = fruits.map((name) => name.toUpperCase());
// [‘BANANA’, ‘MANGO’, ‘APPLE’]

Если функция определяется вне контекста, то к ней применяются те же правила, что и к именованным функциям, то есть типы параметров должны быть заданы во время определения.
const toUpper = (name: string): string => name.toUpperCase();
const upperFruits = fruits.map(toUpper);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

TypeScript: Деструктуризация

A

Деструктуризация в определении функций - механизм, с помощью которого объект переданный как аргумент распаковывается и его части присваиваются локальным переменным функции.
// Обычное определение
function f(user: { firstName: string, age: number }) {
console.log(firstName, age);
}

// Деструктурированный объект
function f({ firstName, age }: { firstName: string, age: number }) {
console.log(firstName, age);
}
Деструктурированный объект все равно остается объектом, поэтому в TypeScript описание его типа идет после закрывающей фигурной скобки. Можно сделать код менее многословным вынеся определение типа в алиас. Все тоже самое применимо и к массивам.
// Деструктурированный массив
function foo([x, y]: number[]) {
console.log(x, y);
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

TypeScript: Иерархия типов (type hierarcy)

A

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

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

  1. Примитивные типы: это базовые типы данных в TypeScript, такие как number, string, boolean, null, undefined, symbol.
  2. Объектные типы: это типы данных, которые представляют собой объекты в JavaScript, такие как объекты, массивы, функции и классы.
  3. Специальные типы: это типы данных, которые имеют особую семантику или поведение в TypeScript, такие как any, unknown, void, never.
  4. Дополнительные типы: это пользовательские типы данных, которые могут быть определены разработчиком. Это может быть простой пользовательский тип, такой как тип перечисления (enum), или составной пользовательский тип, такой как класс или интерфейс.

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

TypeScript: Именованные функции

A

Функции требуют обязательного указания типов всех входных параметров. При таком указании, параметр будет обязательным. Попытка вызвать функцию без параметра приведет к ошибке компиляции.
function getGreetingPhrase(name: string) {
return Hello, ${name.toUpperCase()}!;
}

Чтобы сделать параметр необязательным, нужно добавить знак ? после имени переменной. В таком случае тип переменной name становится составным (Union Type): string | undefined, что читается как “строка или undefined”. Необязательный параметр может быть undefined, но не null.
function getGreetingPhrase(name?: string) {
return Hello, ${name ? name.toUpperCase() : 'Guest'}!;
}

Для добавления null нужно изменить определение так, выйдет string | undefined | null.
function getGreetingPhrase(name?: string | null) {
return Hello, ${name ? name.toUpperCase() : 'Guest'}!;
}

Значение по умолчанию задается как в JavaScript. Сама переменная автоматически становится необязательной, и тип выводится исходя из переданного значения:
function getGreetingPhrase(name = ‘Guest’) {
return Hello, ${name.toUpperCase()}!;
}
getGreetingPhrase() // Hello, Guest!

TypeScript выводит тип возвращаемого значения самостоятельно, но хорошим тоном считается указание его явно:
function getGreetingPhrase(name: string): string {
return Hello, ${name.toUpperCase()}!;
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

TypeScript: Кортежи (Tuples)

A

Обычно массивы могут менять свой размер и содержать ноль или более значений, тем самым пустой массив как значение [] является валидным для массивов любого типа. Но иногда массивы выпуступают в качестве упрощенной версии объекта, где количество значений и их порядок строго определен. Например с помощью такого массива можно представить точку на плоскости: [x, y].
В TypeScript подобные массивы называются кортежами и у них есть свой собственный синтаксис определения. Кортежи могут состоять из элементов разных типов type HTTPResponse = [number, string], а часть из них может быть опциональна const HTTPResponse = [number, string?].

const point: [number, number] = [1, 3]
// Можно поменять
const point[0] = 4;
// Обращение к несуществующему индексу приведет к ошибке
point[5]; // Error!
// Нельзя создать не совпадающий по типу
const point2: [number, number] = [1, 3, 8]; // Error!

Обратите внимание на создание переменных для кортежей. Если используется алиас, то его нужно указывать явно, иначе, с точки зрения TypeScript будет создан обычный массив:
// все хорошо, использован алиас
const response2: HTTPResponse = [201, ‘Created’];
// Будет иметь тип (string | number)[]
const response = [201, ‘Created’];

Важно помнить, что к push() или pop() поведение не применяется, исторически так сложилось. Общая рекомендация состоит в том, чтобы не пытаться изменять размер кортежа.
point.push(10);
console.log(point); // [4, 3, 10];

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

TypeScript: Литералы (Literal Types)

A

TypeScript поддерживает литеральный тип для следующих типов: string, boolean, number и BigInt.
С точки зрения теории множеств, такой тип представляет собой множество, состоящее из одного элемента, а для системы типов это ограничение, что переменной не может быть присвоено ничего, кроме указанного значения:
type TestValue = ‘test’;
let test: TestValue = ‘test’;
test = ‘string’; // Error: Type ‘“string”’ is not assignable to type ‘“test”’.

Они сами по себе не очень практичны, но могут быть объединены для создания мощной (практической) абстракции в объединенном типе:
type CardinalDirection = ‘North’ | ‘East’ | ‘South’ | ‘West’;
function move(distance: number, direction: CardinalDirection) {
// …
}
move(1, ‘North’); // ok
move(1, ‘Nurth’); // Error

Также литеральные типы могут комбинироваться с любыми другими типами, так мы можем получить ограничение, под которое попадают все числа и false:
type NumberFalse = number | false;

Проблема, описанная в этом уроке, в большинстве языков реализуется через перечисления (Enum), но проблема в том, что перечисления — это конструкция языка, которая остается существовать в коде после трансляции кода в JavaScript. По этой причине многие разработчики выбирают вместо них Union Types, которые позволяют сделать практически то же самое с помощью простых типов.

В объектных литералах поля инициализируются одним литеральным типом или их пересечением:
type DataSourceOption = {
type: ‘postgre’ | ‘mysql’; // часто используется в библиотеках, огда от нас ожидают одну из двух разных строк.
host: string;
port: number;
}

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

const ormConfig = {
type: ‘mysql’;
host: ‘localhost’;
port: 5432;
} as const;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

TypeScript: Массивы

A

TypeScript умеет выводить тип массива, но массив — это составной тип данных, который представляет собой контейнер для какого-то другого типа. К примеру, number[] - массив чисел, string[] - массив строк.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

TypeScript: Массивы только для чтения

A

В TypeScript работа с неизменяемыми массивами встроена в систему типов. Чтобы гарантировать неизменяемость, массив помечается модификатором readonly. Он запрещает изменение массива, но не запрещает изменение объектов, находящихся внутри массива
function process(numbers: readonly number[]) {
numbers.push(1); // Error!
}

const items: readonly ({ key: string })[] = [{ key: ‘value’}];
items[0].key = ‘another value’; // ok!

Модификатор readonly, сам по себе является синтаксическим сахаром. Технически, в случае массива readonly меняет тип Array, на тип ReadonlyArray.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

TypeScript: Многомерные массивы (multi dimensional arrays)

A

Для определения многомерных массивов используется синтаксис Type[][].

const items1 = [[3, 8], [10, 4, 8]]; // items1: number[][]
// Используя алиас
type User = {
name: string;
}
// или так Array<User[]>
const users: User[][] = [
[{ name: ‘Eva’}, { name: ‘Adam’ }],
];

Для определения массивов составных типов нужно использовать скобки.
const coll: (string | number)[][] = [];
coll.push([‘hexlet’, 5])

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

TypeScript: Объединения (Union Types)

A

Объединение (пересечение) типов играют большую роль в TypeScript, они позволяют выразить обычную для JavaScript ситуацию, когда возвращаемое значение или аргумент функции могут быть различного типа. Объединение указывается с помощью оператора прямой черты |, по обе стороны которого располагаются типы. В результате мы получаем тип, обещающий содержать переменную одного из типов объединения.
type at = (str: string, position: number) => string | undefined;
Union Types используется повсеместно, где программист хочет сказать, что переменная может содержать значения разных, но заранее описанных типов. Для указания абсолютно произвольных типов может использоваться unknown или более конкретные дженерики, которые рассмотрим дальше в курсе.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

TypeScript: Объектные типы (Object Types)

A

Тип объекта состоит из типов всех входящих в него свойств. Он выводится автоматически:
// Тип: { firstName: string; pointsCount: number; }
const user = {
firstName: ‘Mike’,
pointsCount: 1000,
};
// Поменять тип свойств нельзя
// Type ‘number’ is not assignable to type ‘string’.
user.firstName = 7;

TypeScript не позволяет обращаться к несуществующим свойствам. Это значит, что структура любого объекта должна быть задана при его инициализации.
Как и в случае примитивных типов данных, ни null, ни undefined по умолчанию не разрешены. Чтобы изменить это поведение, нужно добавить опциональность:
// firstName может быть undefined
// pointsCount может быть null
function doSomething(user: { firstName?: string; pointsCount: number | null; }) {…}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

TypeScript: Перегрузка функций (Function Overloads)

A

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

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

function concat(a: number, b: number): string;
function concat(a: string, b: string): string;

function concat(a: any, b: any): string {
if (typeof a === ‘string’) {
return ${a}{b};
} else {
return ${a.toFixed()}{b.toFixed()};
}
}
concat(‘one’, ‘two’); // onetwo
concat(3, 5.34); // 35
concat(1.33, 10); // 110

17
Q

TypeScript: Переменные

A

TypeScript автоматически связывает переменную (или константу) с типом данных значения начального значения. В программировании такой процесс называется выводом типов.
- Тип переменной поменяться не может!
- Если мы попытаемся передать эту переменную в метод, который ожидает другой тип, то это тоже приведет к ошибке
- Статическая типизация накладывает ограничение на массивы, внутри могут храниться данные только одного типа
- нельзя не только менять тип свойств внутри объекта, но и добавлять новые свойства динамически.
- По умолчанию в TypeScript переменные могут содержать только указанный тип без исключений, например мы не можем присвоить null. Если нам важно указать null - в этом случае используется специальный Union Type: let age: number | null = 30. Читается это как: “число или null”.

let name: string = ‘Alice’;
const count: number = 100;
let canPlay: boolean = true;

18
Q

TypeScript: Пересечение (Intersections Types)

A

Пересечение указывается с помощью символа &, по обе стороны от которого располагаются типы.
type OrderStatus = ‘Created’ | ‘Paid’ | ‘Shipped’ | ‘Delivered’;
type Order = {
status: OrderStatus, //определим тип объекта со статусом заказа
}
type OneHundredOrder = Order & {
cost: 100 //затем более строгий тип с точной ценой в сотню
}
const myOrder: OneHundredOrder = { // Тип, который получился в итоге, OneHundredOrder, из пересечения объектного типа с полем status и cost, содержит оба этих поля.
status: ‘Created’,
cost: 100
}
Тем самым мы получили ограничение по объекту, которое требует от значения наличия обоих этих полей с конкретными значениями, так как мы использовали литеральные типы при описании.
С точки зрения теории множеств, при пересечении мы получаем новое множество, содержащее значения, которые есть в обоих множествах. Тем самым если мы объявим переменную const StringAndNumber: string & number, то ей нужно будет присвоить такое значение, которое одновременно принадлежит множествам string и number, то есть является одновременно и строкой, и числом. Когда в теории множеств пересекается два множества, не содержащих общих элементов, то получается пустое множество. В TypeScript есть специальный тип, обозначающий пустое множество, — never.

19
Q

TypeScript: Перечисления (Enums)

A

Перечисление - конструкция языка, позволяющая создать набор имен, объединенных по какому-то удобному признаку, а затем обращаться к ним. Перечисления заменяют собой использование строк для постоянных значений. С их помощью легко и удобно хранить и обращаться к различным справочным данным.
enum OrderStatus {
Created,
Paid,
Shipped,
Delivered,
}
const order = {
items: 3,
status: OrderStatus.Created,
};

Перечисление само по себе является и значением, и типом. Его можно указывать как тип в параметрах функции:
setStatus(status: OrderStatus)

20
Q

TypeScript: Присвоение значения (assignability)

A

Совместимость типов (Types Compatibility) - совокупность правил, на основе которых при анализе типа данных, принимается решение о возможности заменить один тип данных другим таким образом, чтобы замена не нарушила выполнение программы.

Когда видите ошибку Type X is not assignable to type Y. не торопитесь привести все к самому общему типу any, который тем и опасен, что совместим со всеми типами, даже самыми строгими, вроде never. Сперва следует разобраться, что ожидается в вызываемой функции и только с осознанием происходящего модифицировать собственные типы, расширять допустимые или использовать хак с any.
Понимание того, что к чему можно присвоить в TypeScript исходит из понимания иерархии типов и структурной типизации, чему и посвящены следующие уроки.

21
Q

TypeScript: Псевдонимы Типов (Type Aliases)

A

TypeScript позволяет задавать имя (алиас или псевдоним) для составных типов, описание которых будет повторяться из раза в раз в каждом определении функции. Алиас это не создание нового типа данных, а всего лишь способ сокращенно записать определение типа.
type User = {
firstName: string;
pointsCount: number;
}
Теперь можно провести замену во всех функциях:
function doSomething(user: User) {…}

Типы можно задавать для любых типов данных, от простых до составных:
type SomeType = string;
type SomeType = string | number | null;
type Countable = (coll: number[]) => number

Описание типа функции вне объекта и внутри отличается. Когда функция записывается самостоятельно, то используется формат стрелочной функции:
type Countable = (coll: number[]) => number
Внутри типа, описывающего объект, формат меняется на такой же, который используется для обычных свойств:
type User = {
firstName: string;
pointsCount: number;
count(coll: number[]): number;
}
Но это не касается колбеков, которые могут быть использованы внутри:
type User = {
firstName: string;
pointsCount: number;
// Типы взяты для примера
count(coll: (v: string) => string): number;
}

22
Q

TypeScript: Система модулей

A

Система модулей TypeScript была создана до стандартизации ESM модулей. По умолчанию она совместима с nodejs модулями, использует идентичный алгоритм определения импортов и экспортов, при этом синтаксически очень похожа на ESM, где мы используем ключевые слова import/export для импортирования в текущий модуль и экспорта из него, при этом остается валидным использование CommonJS модулей. Как и в ESM стандарте также поддерживается именованный экспорт/импорт и импорт всего экспортированного через import * as smth from ‘./somewhere.

// @file helloWorld.ts
export default function helloWorld() {
console.log(“Hello, world!”);
}
//@file main.ts
import helloWorld from ‘./helloWorld’;

Некоторые пакеты поставляют только типы, для таких случаев есть специальный синтаксис, который позволят импортировать и экспортировать отдельно типы:
// @file user.types.ts
export type User = { name: string };
// @file main.ts
import type { User } from ‘./user.types’;

Если модули решают проблему разнородных сущностей и коллизий с помощью разнесения кода по нескольким файлам, то механизм namespace позволяет оставаться в рамках одного файла. Больше всего этот механизм пригождается авторам библиотек и оберток с типами, они заключают все интерфейсы в один namespace, что упрощает пользователям слияние интерфейсов (тема одного из следующих уроков в курсе), а также гарантию отсутствия коллизий имен.
namespace Hello {
export function helloWorld() {
console.log(“Hello, world!”);
}
}
const helloWorld = Hello.helloWorld();

23
Q

TypeScript: Сужение типа (Narrowing)

A

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

К примеру, в примере ниже параметр имеет тип unknown, но внутри TypeScript позволяет выполнять с этим параметром разные действия, в зависимости от заданных условий. Narrowing работает не только для типа unknown. Это универсальный механизм, который работает со всеми возможными типами, например, Union Types.
function isPresence(value: unknown) {
if (value === null || value === undefined) {
return false;
}
// пустая строка
if (typeof value === ‘string’) {
if (value === ‘’) {
return false;
}
}
// пустой массив
if (Array.isArray(value)) {
if (value.length === 0) {
return false;
}
}
// пустой объект
if (v instanceof Object) {
if (Object.keys(value).length === 0) {
return false;
}
}
return true;
}

Также Narrowing поддерживает switch:
function foo(value: number | string) {
switch (typeof value) {
case ‘number’:
// какая-то логика
break;
case ‘string’:
// какая-то логика
break;
}
}

24
Q

TypeScript: Тип Any

A

Специальный тип any используется там, где проверка типов не нужна, либо, когда TypeScript не может вывести тип данных автоматически.
Использование any превращает TypeScript в JavaScript, так как данные с таким типом перестают проверяться.
any полезен, например, при переводе проекта из JavaScript в TypeScript, когда сначала все типы объявляются как any, а затем понемногу переписываются на нужные.
Кроме того, он нужен для работы с библиотеками JavaScript (у которых нет описанных типов) из TypeScript кода. В остальных случаях any нужно избегать, так как теряется весь смысл использования языка TypeScript.

25
Q

TypeScript: Тип never (возврат из функции)

A

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

26
Q

TypeScript: Тип unknown

A

В TypeScript существует дополнение к any называемое unknown.
Главное отличие unknown от any связано с проверкой типов. unknown запрещает выполнять любые операции:
let value: unknown = ‘code-basics’;
value.toUpperCase(); // Error!
value.trim(); // Error!

Когда нам приходится создавать функцию, которая может работать с любым входящим типом, лучше использовать unknown, тогда TypeScript защитит от потенциальных ошибок типов:
function isError(value: unknown)

Затем, уже внутри тела можно выполнить нужную проверку, чтобы узнать с чем мы имеем дело:
function isError(value: unknown) {
return value instanceof Error;
}

27
Q

TypeScript: Тип Void

A

void указывается как возврат для функций, которые ничего не возвращают. Он автоматически выводится в том случае, когда внутри функции нет инструкции return или она пустая. Void позволяет возвращать любые данные, но делает так, что их использование бессмысленно.
type voidFunc = () => void;
// Тип функции определяется через контекст
// присваивания ее переменной с типом voidFunc
const f: voidFunc = () => {
return true;
};
const v = f();

Единственная ситуация, когда указание void явно запрещает возврат из функции это определение функции вне контекста использования, когда ее тип указывается явно:
function foo(): void {
return true; // Error!
}

const bar = function(): void {
return true; // Error!
};

28
Q

TypeScript: Типы как множества

A

Тип данных — это множество всех значений и набор допустимых операций над ними. Типы обеспечивают типобезопасность.

TypeScript умеет комбинировать типы так, как это делается в обычных множествах. Например, мы можем объединить два множества типов, получив новый тип, в который входят все элементы первого множества (типа) и второго множества (типа). Так появляется Union Type:
type SomeType = number | string;
const v1: SomeType = 1;
const v2: SomeType = ‘hexlet’;

29
Q

TypeScript: Функции как параметры

A

В TypeScript используется несколько способов типизировать функции передаваемые как параметры. Самый простой - использовать тип Function. Он описывает собой функцию JavaScript со всеми ее особенностями включая свойства bind, call и apply. Function отключает проверку типов для вызываемой функции. Никак не проверяется количество и тип входных аргументов, а результатом работы такой функции будет any.
function process(callback: Function) {
const value = callback(); // …
}

Другой способ описывать функции - использовать стрелочную функцию с указанием входных и выходных типов.
function process(callback: () => number)
function process(callback: () => string[])
function process(callback: () => { firstName: string; })
Пример с параметрами:
function process(callback: (n: number) => string) {
const value = callback(10);
}