Перейти к содержимому

Void typescript что это

  • автор:

TypeScript: Тип Void

В этом уроке мы рассмотрим тип 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 . Он позволяет возвращать любые данные, но делает так, что их использование бессмысленно.

Мы можем определить тип функции, который возвращает void , и использовать его для типизации переменной:

type VoidFunc = () => void; // Тип функции определяется через контекст // присваивания ее переменной с типом VoidFunc const f: VoidFunc = () => true; const v = f(); 

Хотя f() возвращает true , переменная v имеет тип void . Это означает, что мы не можем использовать ее для чего-либо, кроме как для присваивания другой переменной с типом void .

Существует единственная ситуация, когда указание void явно запрещает возврат из функции. Это определение функции вне контекста использования, когда ее тип указывается явно:

function foo(): void < return true; // Error! >const bar = function(): void < return true; // Error! >; 

В этом случае возврат любого значения приведет к ошибке компиляции.

Также void является оператором JavaScript, поэтому важно не запутаться с ним. Он вычисляет выражение, которое следует за ним и возвращает undefined :

void 10 === undefined // true 

Задание

Попробуйте самостоятельно определить функцию forEach() для чисел:

forEach([1, 2, 3], (n) => console.log(n)); // 1 // 2 // 3 const result = []; forEach([1, 2, 3], (n) => result.push(n)); // [1, 2, 3] 
  1. Массив чисел
  2. Анонимная функция, которая принимает на вход число и возвращает void . У этой функции есть необязательный параметр — индекс элемента в массиве
forEach([8, 9], (n, index) => console.log(index + n)); // 8 // 10 

Упражнение не проходит проверку — что делать? ��

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

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

В моей среде код работает, а здесь нет ��

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

Мой код отличается от решения учителя ��

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

В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.

Прочитал урок — ничего не понятно ��

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

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

Полезное

  • Официальная документация
  • void в TypeScript и JavaScript

В чем разница между void и never в TypeScript?

В TypeScript есть два псевдо-типа данных обозначающих «ничто»: void и never . Чем они отличаются и как понять когда применять void , а когда never ?

Отслеживать
задан 28 июн 2017 в 18:53
Dmitriy Simushev Dmitriy Simushev
17.9k 5 5 золотых знаков 48 48 серебряных знаков 85 85 бронзовых знаков
Тут неплохой ответ: stackoverflow.com/questions/37910669/…
28 июн 2017 в 20:32

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

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

function f(): never

Псевдо-тип void означает, что функция возвращает undefined . Это происходит в случае, если поток выполнения доходит до конца функции, не встретив конструкции return :

function f(arg): void

или когда конструкция return используется без указания аргумента:

function f(arg): void < if (arg < 0) < return; >console.log(arg); > 

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

Тип Void — Основы Typescript

В этом уроке мы рассмотрим тип 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 студентов

Наши выпускники работают в компаниях:

Примитивные типы 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 = <> 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *