Learning Book

this-параметр и void

Объявление this в функциях

TypeScript выводит тип this из контекста потока кода. Но иногда нужен более точный контроль. Спецификация TypeScript позволяет объявить тип this как специальный первый параметр функции:

const user = {
  id: 123,
  admin: false,
  becomeAdmin: function () {
    this.admin = true; // TypeScript выводит тип this
  },
};

Для коллбэков, которые будут вызваны в другом контексте, this-параметр критически важен:

interface DB {
  filterUsers(filter: (this: User) => boolean): User[];
}

const db = getDB();

// ✅ Правильно: обычная функция
const admins = db.filterUsers(function (this: User) {
  return this.admin;
});

Параметр this не существует в рантайме – TypeScript удаляет его при компиляции. Он нужен только для проверки типов.

// ❌ Ошибка: стрелочная функция не имеет собственного this
const admins2 = db.filterUsers((this: User) => {
  return this.admin;
});

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

void

Тип void означает, что функция ничего не возвращает. Это не то же самое, что undefined:

// Тип возврата — void
function noop(): void {
  return; // OK: return без значения
}

Важная особенность: контекстуальная типизация с типом возврата void не запрещает функции что-то возвращать. Это позволяет писать такой код:

type VoidFunc = () => void;

const f1: VoidFunc = () => {
  return true; // OK! Возвращаемое значение игнорируется
};

const f2: VoidFunc = () => true; // OK!

// Но: тип результата — void, не boolean
const v1 = f1(); // тип: void

Это поведение по замыслу – оно позволяет использовать Array.prototype.forEach с коллбэками, которые что-то возвращают:

const src = [1, 2, 3];
const dst: number[] = [];

// push возвращает number, но forEach ожидает () => void
// Это работает благодаря void-совместимости
src.forEach((el) => dst.push(el));

Однако если функция явно объявляет возврат void, она действительно не должна ничего возвращать:

function fail(): void {
  // ❌ Ошибка: нельзя возвращать значение из функции с типом void
  // return true;
}

object

Тип object описывает любое значение, которое не является примитивом (string, number, bigint, boolean, symbol, null, undefined). Это не то же самое, что Object или {}:

function acceptObject(obj: object) {
  // OK: массивы, функции, объекты
}

acceptObject({ name: "Алиса" }); // OK
acceptObject([1, 2, 3]);         // OK
acceptObject(() => {});           // OK

// acceptObject("строка");        // ❌ Ошибка: string — примитив
// acceptObject(42);              // ❌ Ошибка: number — примитив

unknown

Тип unknown – безопасная альтернатива any. Переменной типа unknown можно присвоить что угодно, но использовать её нельзя без сужения типа:

function safeParse(s: string): unknown {
  return JSON.parse(s);
}

const result = safeParse('{"x": 1}');
// result.x;  // ❌ Ошибка: нельзя обращаться к свойствам unknown

if (typeof result === "object" && result !== null && "x" in result) {
  console.log(result.x); // ✅ OK после сужения
}

В контексте функций unknown безопаснее any для параметров-обработчиков:

function processValue(val: unknown) {
  if (typeof val === "string") {
    console.log(val.toUpperCase()); // TypeScript знает, что val — string
  }
  if (typeof val === "number") {
    console.log(val.toFixed(2)); // TypeScript знает, что val — number
  }
}

never

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

function throwError(message: string): never {
  throw new Error(message);
}

function infiniteLoop(): never {
  while (true) {
    // бесконечный цикл
  }
}

never также появляется при исчерпывающих проверках (exhaustive checks):

function handleShape(shape: "circle" | "square") {
  switch (shape) {
    case "circle":
      return Math.PI;
    case "square":
      return 4;
    default:
      // shape имеет тип never — все варианты обработаны
      const _exhaustive: never = shape;
      return _exhaustive;
  }
}

Function

Глобальный тип Function описывает свойства bind, call, apply и другие, присутствующие у всех функций в JavaScript. Значения типа Function можно вызывать – результат будет any:

function doSomething(f: Function) {
  const result = f(1, 2, 3); // тип result — any
}

Это нетипизированный вызов, и его лучше избегать. Если нужно принять произвольную функцию, используй () => void:

// ✅ Лучше: типизированная альтернатива
function doSomething(f: () => void) {
  f();
}

Итого

ТипЗначение
voidФункция ничего не возвращает (но void-коллбэки могут)
objectЛюбое не-примитивное значение
unknownБезопасная альтернатива any (требует сужения)
neverЗначение никогда не появится (throw, бесконечный цикл)
FunctionНетипизированная функция (лучше избегать)
this: TypeОбъявление типа this для коллбэков (удаляется при компиляции)