Стендап WTF TypeScript

от автора

Эта статья — вольный перевод свежего стрима 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]


ссылка на оригинал статьи https://habr.com/ru/articles/927182/


Комментарии

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

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