Эта статья — вольный перевод свежего стрима ThePrimeTimeagen (бывший разработчик Netflix, харизматичный чувак с усами)

"I'm just the normy, but everyone is so bad at their crap, so I just rise to the top"

Цитата:
«Я просто обычный разработчик, но все вокруг настолько плохо справляются со своей работой, что на их фоне я кажусь топовым»

Я понимаю что вся эта информация в текстовом виде не очень то похожа на стендап, поэтому очень советую посмотреть оригинальный стрим. Многие примеры я видела впервые и мне было реально смешно :)

WTF №1 — Проверка лишних свойств

У нас есть тип, который имеет свойства firstName и age, а также функция, которая принимает объект типа Person и просто печатает его:

type Person = { firstName: string, age: number };

function logPerson(person: Person) {
	console.log(person);
}

Чтобы вызвать функцию, мы просто сделаем вот так:

logPerson({ firstName: 'trash', age: 21 });

И это — совершенно ожидаемое поведение. Если мы передадим лишнее поле, то получим ошибку:

logPerson({ firstName: 'trash', age: 21, extraProp: 21 }); // ошибка

Object literal may only specify known properties, and 'extraProp' does not exist in type 'Person'.ts(2353)

Screenshot 2025-07-12 at 18.46.06.png

Но есть одна интересная деталь: если мы вынесем объект в переменную и передадим её в функцию, ошибки не возникает:

const person = {
	firstName: 'trash',
	age: 21,
	extraProp: 21
};

logPerson(person); // нет ошибки

Мы можем отловить ошибку, если укажем тип объекта явно:

const person: Person = {
	firstName: 'trash',
	age: 21,
	extraProp: 21 // Object literal may only specify known properties, and 'extraProp' does not exist in type 'Person'.ts(2353)
};

Но даже в этом случае, если мы очень захотим добавить дополнительное свойство, то можно обойти ограничение:

const person: Person = {
	firstName: 'trash',
	age: 21,
	...{ extraProp: 21 } // ошибки нет
};

WTF №2 — Enums

У нас есть Enum с цветами и функция, которая принимает конкретное значение из этого Enum. Если мы передадим Colors.Green, всё работает. Но если передать строку, совпадающую по значению, то ничего не получится

enum Colors {
	Green = 'green',
	Orange = 'orange',
	Red = 'red',
}

function isTheBestColor(color: Colors) {
	// some code
}

isTheBestColor(Colors.Green); // работает ❤️

isTheBestColor('green'); // не работает ?

Но...

Если использовать Enum с числовыми значениями:

enum Status {
	Pending = 0,
	Declined = 1,
	Approved = 2,
}

function validateStatus(status: Status) {
	// some code
}

// работает ❤️
validateStatus(Status.Declined);

// работает!? ?‍?
validateStatus(1);

Некоторые разработчики предпочитают такую запись, чтобы обойти Enum:

const Foo = {
  FAILED: 'failed',
  SUCCESS: 'success',
} as const;

type Bar = typeof Foo;
type BarKeys = keyof Bar;
type BarValues = Bar[BarKeys];

const x = (f: BarKeys) => f;
x('FAILED');

const y = (f: BarValues) => f;
y('failed');

Такая запись позволяет при вызове соответствующей функции сразу выбирать из предзаполненных вариантов и видеть конкретное значение в реальном времени при логировании

WTF №3 — .filter()

Существует популярный способ отфильтровать все falsy-значения с помощью filter

const arr = [1, undefined, 3].filter(Boolean);

console.log(arr); // [1, 3]

В этом примере мы ожидаем, что тип arr будет number[], но на самом деле получаем (number | undefined)[], потому что TypeScript не может точнее определить тип возвращаемого значения. Это неудобно: ты точно знаешь, что в рантайме undefined не будет, но в типах обязан это учитывать

WTF №4 — {} vs object vs Object

Существует несколько способов описать объект.

Когда мы хотим создать пустой объект, обычно пишем let foo = {}, но забавно, что мы можем присвоить этой переменной любое примитивное значение — кроме null и undefined. Если же задать тип явно как object, он работает ожидаемо — не принимает примитивы

let foo: object;

foo = { hello: 0 };   ✅  
foo = [];             ✅  
foo = false;          ❌  
foo = null;           ❌  
foo = undefined;      ❌  
foo = 42;             ❌  
foo = 'bar';          ❌  

А теперь let foo: {}

foo = { hello: 0 };   ✅  
foo = [];             ✅  
foo = false;          ✅  
foo = null;           ❌  
foo = undefined;      ❌  
foo = 42;             ✅  
foo = 'bar';          ✅  

WTF №5 — Бонусный

У нас есть массив строк и функция, которая принимает массив строк или чисел. Ошибки нет, хотя после изменения тип массива остаётся прежним. WTF?

const foo: string[] = ["1", "2"];

function bar(thing: (number | string)[]) {
    thing.push(3);
}

bar(foo);

console.log(foo); // ['1', '2', 3]

Комментарии (19)


  1. alpo-tech
    14.07.2025 05:21

    Переходим на rust


  1. ImagineTables
    14.07.2025 05:21

    WTF?


  1. jeny_tat
    14.07.2025 05:21

    Мне про TypeScript понравился коммент одного разраба: "TypeScript делает простые вещи сложными, а сложные вещи простыми". И в итоге Макрософт пытались с помощью TypeScript обуздать "чудовище" (JS), которое они однажды создали, но как-то не туда все пошло опять


    1. devprodest
      14.07.2025 05:21

      Да ладно вам, будто в плюсовом мире меньше идиотизма.


    1. Galy4a
      14.07.2025 05:21

      А когда это Майкрософт создал JS?


    1. nihil-pro
      14.07.2025 05:21

      TypeScript делает простые вещи сложными, а сложные – any.