Заметка о 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?


FavoriteLoadingДобавить в избранное
Posted in Без рубрики

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

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