PurpleSchool — курсы программирования онлайн
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    TypeScript 4.9 - satisfies, улучшение in и NaN

    TypeScript 4.9 - satisfies, улучшение in и NaN

    Аватар автора TypeScript 4.9 - satisfies, улучшение in и NaN

    Антон Ларичев

    Иконка календаря23 января 2023

    Сегодня разберём, что же нового добавили в TypeScript 4.9 и чем это будет для нас полезно.

    Оператор satisfies

    Начнём с оператора satisfies, который поможет нам улучшить типизацию наших объектов. При этом не ограничивая нас, если объекты создали мы сами.

    Пример:

    Сделаем обычную типизацию ошибки:

    // Тип ErrorData
    type ErrorData = {
      errorOrCode: number | string; // код ошибки
      payload?: Record<string, string | number | boolean>; //payload (опциональный)
    };
    
    // Пример errorData
    const errorData: ErrorData = {
      errorOrCode: 'TIMEOUTERROR',
      payload: {
        userId: 1,
      },
    };
    

    У нас есть некоторые данные ошибки errorData и их тип ErrorData:

    • errorOrCode - код ошибки, который будет number либо string. Может прийти как 404 либо как TIMEOUTERROR.
    • payload - является опциональным. Содержит внутри объект, где ключом будет string, а значениями: string либо number, либо boolean.

    Создаем объект ошибки, чтобы потом его передать, но это не JS поэтому нам надо типизировать errorData. Изначально мы все написали корректно. Теперь специально сделаем опечатку в слове payload:

    // тип ErrorData
    type ErrorData = {
      errorOrCode: number | string; // код ошибки
      payload?: Record<string, string | number | boolean>; //payload (опциональный)
    };
    
    // данные errorData
    const errorData: ErrorData = {
      errorOrCode: 'TIMEOUTERROR',
    
      // Ошибка!!! TypeScript пишет, что "paload" не существует в типе "ErrorData": "возможно вы хотели записать "payload"?"
      paload: {
        userId: 1,
      },
    };
    

    Казалось бы теперь все хорошо и мы двигаемся дальше. Давайте попробуем преобразовать данные ошибки в нижний регистр:

    // тип ErrorData
    type ErrorData = {
      errorOrCode: number | string; // код ошибки
      payload?: Record<string, string | number | boolean>; //payload (опциональный)
    };
    
    // данные errorData
    const errorData: ErrorData = {
      errorOrCode: 'TIMEOUTERROR',
      payload: {
        userId: 1,
      },
    };
    
    // пытаемся перевести в нижний регистр
    errorData.errorOrCode. // отсутсвует метод toLowerCase()!
    

    Видим, что отсутсвует метод toLowerCase(). Всё потому, что errorOrCode можеть быть как string так и как number. Поэтому мы не можем просто так написать toLowerCase(). для этого нужно сделать проверку:

    if (typeof errorData.errorOrCode == 'string') {
      errorData.errorOrCode.toLowerCase();
    }
    

    Ещё хуже обстоят дела с userId:

    // и здесь пишет, что нет никакого 'userId' и 'payload' является опциональным
    errorData.errorOrCode.userId;
    

    Поэтому мы тут практически начинаем бороться с типизацией. Вот именно тогда на помощь к нам приходит satisfies.

    Вместо того чтобы говорить, что объект errorData точно будет типа 'ErrorData', мы можем применить оператор satisfies. Мы говорим, что объект может быть любым, но главное, чтобы он удовлетворял интерфейсу или в данном случае типу ErrorData:

    satisfies ErrorData;
    

    Теперь можно убрать всякие условия и всё будет работать:

    // тип ErrorData
    type ErrorData = {
      errorOrCode: number | string; // код ошибки
      payload?: Record<string, string | number | boolean>; //payload (опциональный)
    };
    
    // данные errorData
    const errorData = {
      errorOrCode: 'TIMEOUTERROR',
    
      // Ошибка!!! TypeScript пишет, что "paload" не существует в типе "ErrorData": "возможно вы хотели записать "payload"?"
      paload: {
        userId: 1,
      },
    } satisfies ErrorData; // применяем оператор `satisfies`
    
    // всё работает
    errorData.errorOrCode.toLowerCase();
    errorData.errorOrCode.userId;
    

    Оператор in

    Он позволяет нам отделить один интерфейс от другого:

    type A = {
      a: 1;
      b: 2;
    };
    
    type B = {
      a: 1;
      c: 3;
    };
    
    type C = A | B;
    
    function myf(c: C) {
      if ('c' in c) {
        c; // принимает значение 'B'
      }
    }
    

    И здесь c принимает значение B, потому что мы отделили их по свойству. Благодаря этому мы можем легко сузить наши типы в рамках работы с функцией.

    Однако есть ситуации, когда in нам не поможет:

    type externalData = unknown; // тип, который приходит извне
    
    // передается 'data' типа 'externalData'
    function getExternalData(data: externalData) {
      // делаем проверку
      if (typeof data == 'object' && !!data && 'userId' in data) {
        // обращаемся к свойству
        data.userId; // Ошибка!!! Свойство "userId" не существует в типе "object"
      }
    }
    

    Хотя проверили, что это object, не null и что это свойство есть. Однако ошибка все равно возникает. А в версии TypeScript 4.9:

    type externalData = unknown;
    
    function getExternalData(data: externalData) {
      if (typeof data == 'object' && !!data && 'userId' in data) {
        data.userId // ошибки нет
    }
    

    Все отлично, ошибок нет.

    Сравнение с NaN

    Часто можно встретить как ошибку на код-ревью:

    let a = 10;
    
    // делаем проверку
    if (a !== Nan) {
      // TypeScript теперь подсвечивает выражение: 'Вы хотели использовать "!Number.isNaN(a)"?'
    }
    

    И теперь не будет таких простых ошибок с работой с NaN, так как TypeScript теперь нам сообщает, что мы тут неправы.

    Иконка глаза20 451

    Комментарии

    0

    Постройте личный план изучения Основы разработки до уровня Middle — бесплатно!

    Основы разработки — часть карты развития Frontend, Backend, Mobile

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Основы Git

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    HTML и CSS

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    CSS Flexbox

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    бесплатно
    Подробнее

    Похожие статьи

    Картинка поста CLAUDE.md: как написать инструкции для Claude Code
    Иконка аватараАнтон
    Иконка календаря11 октября 2026
    AI-инструментыClaude CodeDevOps+ 1middleИконка уровня middle

    CLAUDE.md: как написать инструкции для Claude Code

    CLAUDE.md — это файл с инструкциями по проекту, который Claude Code читает в начале каждой сессии. Положите его в корень репозитория и опишите внутри, чем проект собирается, чем запускаются тесты и каких соглашений держаться в коде. После этого агент перестанет спрашивать одно и то же в каждом новом диалоге и предлагать решения, которые в вашей кодовой базе не приняты. Формат предельно простой: обычный Markdown, обязательных полей нет, заголовки любые. Дальше — где именно создавать файл и как Claude Code собирает инструкции сразу из нескольких мест, что писать внутрь, как подключать к файлу другие документы и чем CLAUDE.md отличается от AGENTS.md. Одна оговорка перед началом: Claude Code обновляется часто, набор команд и поддерживаемых файлов пополняется. Если какая-то деталь ниже ведёт себя у вас иначе, сверяйтесь с документацией той версии, которая стоит у вас.

    Иконка чипа0
    Иконка глаза79
    Иконка комментариев0
    Иконка аватараАнтон
    Иконка календаря10 октября 2026
    AI-инструментыClaude CodeDevOps+ 2middleИконка уровня middle

    Агенты в OpenCode: как создать своего агента

    Агент в OpenCode — это именованный профиль работы: своя модель, свой системный промпт и свой список разрешённых инструментов. Чтобы создать своего агента, нужно описать его отдельным markdown-файлом в папке `.opencode/agent/` внутри проекта (или в `~/.config/opencode/agent/`, если агент нужен во всех проектах) либо объявить его в блоке `agent` файла `opencode.json`. После этого агент появляется в списке доступных, и его можно вызвать прямо в сессии.

    Иконка чипа0
    Иконка глаза149
    Иконка комментариев0
    Картинка поста Распределенные системы роутинга на примере Framework Foton
    Иконка аватараКонстантин
    Иконка календаря09 октября 2026
    распределениероутингfotonseniorИконка уровня senior

    Распределенные системы роутинга на примере Framework Foton

    Распределенные системы не только снижают нагрузку, но и формируют более прозрачную, тонкую и гибку архитектуру в монолитном приложении

    Иконка чипа0
    Иконка глаза99
    Иконка комментариев0
    Иконка чипа+1