В чем разница между типами void и never в TypeScript
Что проверяют
Понимаете ли вы, что void про завершение без значения, а never про недостижимость.
Как отвечать
void это тип функции, которая завершается, но не возвращает осмысленного значения. Фактически возвращается undefined.
never это тип значения, которого не существует. Функция с таким типом возврата не завершается нормально: она либо бросает исключение, либо крутится вечно.
function log(msg: string): void { console.log(msg); }
function fail(msg: string): never { throw new Error(msg); }never это нижний тип: он подтип всех типов, поэтому значение типа never присваивается куда угодно, а вот присвоить never нельзя ничего.
Главное практическое применение never это проверка на полноту:
function area(s: Shape): number {
switch (s.kind) {
case "circle": return Math.PI * s.r ** 2;
case "square": return s.a ** 2;
default: {
const exhaustive: never = s; // ошибка компиляции, если добавили новый вид
throw new Error(`неизвестная фигура: ${exhaustive}`);
}
}
}Добавили новый вариант в объединение и забыли обработать, значит проект не соберётся. Это одна из самых полезных возможностей языка.
never встречается и в других местах: пустое объединение, результат пересечения несовместимых типов, ветка условного типа, которую надо выкинуть (так работает Exclude), тип пустого массива never[].
Тонкость про void, которая часто удивляет: функция, возвращающая значение, совместима с типом, возвращающим void. Это сделано намеренно, чтобы arr.forEach(x => arr2.push(x)) компилировался, хотя push возвращает число. При этом присвоить результат такого вызова переменной нельзя, тип всё равно void.
Где спотыкаются
Используют void там, где функция всегда бросает исключение.
Не знают про проверку на полноту через never.
Пытаются присвоить значение переменной типа never.
Удивляются, что колбэк с возвращаемым значением подходит под тип void.