Typescript, присваивающий значение переменной через логический оператор, использует только последний тип - PullRequest
0 голосов
/ 30 января 2020

с учетом следующих типов

enum Modes {
  error,
  warning
}

type Notification = {
  title: string;
  text: string;
};

type CustomNotification = Notification & { mode: Modes };

interface Options {
  defaultNotification: Notification;
  customNotification?: CustomNotification;
}

Я хочу присвоить переменную customNotification, если она доступна, в противном случае - defaultNotification, поэтому я использую логический оператор ИЛИ в присваивании, как:

const notification = customNotification || notificationDefault;

тогда я хочу условно выполнить logi c в зависимости от значения mode, если доступно.

if (notification.mode && notification.mode !== Modes.error) { /** code here */ }

Однако notification назначается только для типа Notification чем CustomNotification | Notification, поэтому машинопись выдает ошибку при попытке прочитать notification.mode значение Property 'mode' does not exist on type 'Notification'.

Я даже пытался явно присвоить тип notification для CustomNotification | Notification, но это не сработало.

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

1 Ответ

2 голосов
/ 30 января 2020

Основная проблема заключается в том, что mode - это поле, которое не существует ни в одном члене Notification | CustomNotification union. Проверка поля mode на наличие объекта Notification запрещена, так как у него нет такого поля. Ниже мои предложения о том, как справиться с вашей проблемой.

Решение одно - объединение типов с режимом по умолчанию

Я бы рассмотрел вместо того, чтобы иметь здесь двойные типы, иметь один тип и вводить внутрь Modes какой-то нейтральный элемент позволяет сказать - default, когда мы делаем так, чтобы проблема всех типов go отсутствовала, и нам не нужно делать никаких утверждений типа или защитников. Рассмотрим:

enum Modes {
  error,
  warning,
  default, // neutral value
}

type Notification = {
  title: string;
  text: string;
  mode: Modes;
};

interface Options {
  defaultNotification: Notification;
  customNotification?: Notification;
}

// getting active notification helper
const getNotification = (options: Options): Notification => {
    return options.customNotification ?? options.defaultNotification;
}

// using
const notification = getNotification(options);
if (notification.mode !== Modes.error) { /** code here */ }

Единственное, что нам нужно сделать, это установить defaultNotification для объекта с mode равным Modes.defalut.

Решение два - режим как явное неопределенное поле

В конце концов, если вы хотите сохранить Modes в текущей форме, мы можем ввести поле mode как поле undefined в defaultNotification. Рассмотрим следующее:

type BaseNotification = {
  title: string;
  text: string;
};

type DefNotification = BaseNotification & { mode?: undefined } // pay attention here
type CustomNotification = BaseNotification & { mode: Modes }

type Notification = DefNotification | CustomNotification;

interface Options {
  defaultNotification: DefNotification;
  customNotification?: CustomNotification;
}

const getNotification = (options: Options): Notification => {
    return options.customNotification ?? options.defaultNotification;
}

Главное здесь - { mode?: undefined }, мы говорим, что наше DefNotification имеет поле mode, но единственное возможное значение для него - undefined.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...