Лучший способ проверить наличие неложных значений в JS/TS?

Я публикую сообщение, чтобы узнать, есть ли у кого-нибудь более чистый способ проверки неложных значений в файлах JS/TS.

За прошедшие годы у меня было несколько попыток написать более понятные операторы if для проверки неложных значений, поскольку это заставляло меня задуматься о том, что все они делают одно и то же, но довольно длинные и в конечном итоге занимают половину некоторых файлов кода.

Я пробовал создавать функции и вводить их разными способами, чтобы инкапсулировать журналирование и затем выдавать ошибки, но TS не воспринимает это как безопасную проверку. Пока что единственное, что удовлетворяет проверке, — это стандартный оператор if с ошибкой, выдаваемой непосредственно в теле.

Нет ли лучшего и менее подробного способа обработки этих повторяющихся проверок, сохраняя при этом безопасность?

Стандартные проверки

 // Not falsy check
     if (!plan) {
        Log.log.stripe_webhook("Plan not found");
        throw new Error("Plan not found");
      }

  // Another not falsy check
      if (!currentUser.email) {
          Log.log.stripe_webhook("Current user does not have an email");
         throw new Error("Current user does not have an email");
       }

Вещи, которые я пробовал

Вспомогательные функции. Со временем я попробовал несколько вариантов, но вот базовый пример, который TS не принимает.

// Function to ensure no false values. TS does not accept this as safe.
            function ensureNotFalsy(
              condition: any,
              errorMessage: string
            ): void {
              if (!condition) {
                Log.log.stripe_webhook(errorMessage);
                throw new Error(errorMessage);
              }
            }

            // Not falsy checks
            ensureNotFalsy(orgRef, "Organization reference not found");
            ensureNotFalsy(orgRef?.organization, "Organization not found");
            ensureNotFalsy(
              orgRef!.organization!.id,
              "Organization ID not found"
            );

  // ...Code below will still throw errors saying these checked values could be undefined.

Добавление ошибок и обработка в const. Тоже не работает. TS, кажется, требует, чтобы ошибка была выброшена в каждом операторе if.

 // Put logic in a const. TS doesn't recognize it as a safe.
        const throwError = (message: string) => {
            Log.log.stripe_webhook(message);
            throw new Error(message);
         };

          // Checks to ensure not falsy. Doesn't work with TS.
          if (!plan) throwError("Plan not found");
          if (!currentUser.email)
          throwError("Current user does not have an email");

  // ...Code below will still throw errors saying these checked values could be undefined.

Пример скриншота

«Нет ли лучшего и менее многословного способа обработки этих повторяющихся проверок, сохраняя при этом безопасность?» - безопасная практика программирования заключается в том, чтобы никогда не иметь объекты в промежуточном состоянии, в котором они могут иметь свойства или нет. Перемещайте больше конкретных объектов меньшего размера, а не большой мутировавший объект с дополнительными свойствами. Вот почему вы чувствуете, что язык «работает против вас», вы можете сделать дополнительные параметры эргономичными с помощью ?. и ?? и сохранить согласованные схемы для остального.

Benjamin Gruenbaum 11.08.2024 23:12

Кроме того, вы описываете Assert, и он выполняет защиту типа (поэтому он проверяет тип свойства, о котором вы беспокоитесь). Просто это не очень распространенный/популярный способ написания кода на TS/JS.

Benjamin Gruenbaum 11.08.2024 23:13

Привет @BenjaminGruenbaum, спасибо за ответ! В ответ на ваш первый комментарий: я довольно строг, когда дело касается чистого, хорошо структурированного и не подробного кода. Я часто трачу 3/4 своего времени на структурирование файла после написания логики, чтобы обеспечить отсутствие избыточности и простоту. Однако довольно часто, особенно в пошаговых процессах, новые значения вводятся поэтапно и не всегда могут быть определены как единый исходный объект. Описанная мной ситуация редко связана с мутациями, поскольку я обычно печатаю измененное значение, чтобы обеспечить типобезопасность.

Max Pauwels 11.08.2024 23:24

Вы пробовали функции утверждения? typescriptlang.org/docs/handbook/release-notes/…

Guillaume Brunerie 11.08.2024 23:29

Я не чувствую, что язык работает против меня, я люблю TS, но эти слишком простые утверждения if для неложных значений раздражали меня в течение многих лет, поскольку все они выполняют одну и ту же задачу и занимают так много места. Я вообще редко использую операторы if. Я обнаружил, что 90% операторов if, которые я вижу в коде, обычно можно переписать более понятным и эффективным способом. И одна вещь, которую я действительно ненавижу, — это просматривать файлы и видеть код, написанный разработчиком, который содержит сотни строк операторов if для процессов, которым следует давать имена, добавлять помощники или вместо них использовать операторы переключения.

Max Pauwels 11.08.2024 23:30

@GuillaumeBrunerie, я пытался подтвердить, но TS также не считает это безопасным. При использовании утверждения для проверки неложных значений исходный код, использующий эти значения, по-прежнему считает их потенциально неопределенными. Вот ответ GPT о том, почему это не работает: TypeScript's type system does not automatically infer non-nullability from assertions or similar checks by default. TypeScript treats assertions as any other function calls that don't return, but it doesn't understand that they confirm the existence or type of variables unless explicitly told so.

Max Pauwels 11.08.2024 23:34

Функции утверждения разработаны именно для этого варианта использования. Ответ от ChatGPT не имеет никакого смысла.

Guillaume Brunerie 11.08.2024 23:38

Кроме того, предположим, что вы хотите сократить количество операторов if, проверяя несколько неложных значений за одну проверку. При этом нет прямого способа вернуть настроенную ошибку или журнал, чтобы указать, какое значение не определено, поскольку JS не знает имени значения имени, поэтому вам в конечном итоге придется выдать общую ошибку и журнал, что не всегда принимается в производственном коде. Мой любимый способ справиться с этим — использовать анализ Zod, но не всегда возможно создать схемы Zod для каждого значения.

Max Pauwels 11.08.2024 23:39

@GuillaumeBrunerie ниже приведен пример, основанный на исходном коде, которым я поделился, с заменой операторов if на Assert. Тс не принимает ни одного из них. // Asserts check assert.ok(orgRef && orgRef.organization, "Organization not found"); const plan = getPlanProductBy("stripe_price_id", stripePrice); assert.ok(plan, "Plan not found"); try { await createSubscription({ plan_id: plan.id, // TS considers this as possibly null organizationId: orgRef.organization?.id, // Same here

Max Pauwels 11.08.2024 23:42

Проверьте мой ответ, функции утверждения работают. Я не понимаю, что вы имеете в виду под assert.ok.

Guillaume Brunerie 11.08.2024 23:45

@GuillaumeBrunerie, ты имеешь в виду это, верно? nodejs.org/api/assert.html#assertokvalue-message У вас есть пример?

Max Pauwels 11.08.2024 23:46

@MaxPauwels Нет, я имею в виду функции утверждения в Typescript, а не в Node. Посмотрите ссылку, которую я дал выше и в моем ответе.

Guillaume Brunerie 11.08.2024 23:48

@GuillaumeBrunerie, это действительно работает! Я не знал об этом; Я действительно ценю совет!

Max Pauwels 11.08.2024 23:54
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
13
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Функции утверждения созданы именно для этой цели. Просто используйте asserts condition вместо void для возвращаемого типа ensureNotFalsy, и все должно работать.

Вот пример:

function ensureNotFalsy(
  condition: any,
  errorMessage: string
): asserts condition {
  if (!condition) {
    throw new Error(errorMessage);
  }
}

const f = (orgRef: {organization?: {id?: string}} | null) => {
  ensureNotFalsy(orgRef, "Organization reference not found");
  ensureNotFalsy(orgRef.organization, "Organization not found");
  ensureNotFalsy(
    orgRef.organization.id,
    "Organization ID not found"
  );
}

Ссылка на игровую площадку

Именно то, что я искал; Спасибо!

Max Pauwels 11.08.2024 23:56

Другие вопросы по теме