Запретить null но разрешить undefined во входных параметрах Vue 3

Странно как-то обстоят дела с понятием "опциональности" входных параметров (props) во Vue 3 (может и в 2, но это не актуально). Если если входной параметр помечен как required: false, то и undefined и null будут расценеы так пустое значение и никаких предупреждений в консоль не будет выдано:

export default {
  props: {
    label: {
      type: String,
      required: false
    }
  }
};

В этом случае валидатор validator (если он есть) выполнен не будет:

export default {
  props: {
    label: {
      // Не будет вызван, когда значение `null`
      validator: value => typeof value == "string" && value.length > 0,
      required: false
    }
  }
};

При этом, если указано значение по умолчанию default, то оно будет подставлено только когда значение входного параметра undefined, не не когда null.

export default {
  props: {
    label: {
      validator: value => typeof value == "string" && value.length > 0,
      default: "DEFAULT" // Не будет поставлен, когда значение - `null`
    }
  }
};

Как же при таком раскладе исключить null? Нужно каждый опциональный параметр теперь как на null, так и на undefined проверять, или каждый из них обкладывать computed-ами? Слишком много рутин для середины 2020-х. Нужно что-то, что берёт эти рутины на себя.


Ответы (1 шт):

Автор решения: Stepan Turbasov

Я тоже один раз столкнулся с такой проблемой, мне нужно было четко различать null и undefined в props, потому что null означал

"пользователь намеренно сбросил значение"

а undefined

"значение не передано, используй дефолт"

Но Vue ведёт себя одинаково и с null, и с undefined — ни валидация не вызывается, ни default не подставляется, если required: false.

Я прям напрягся, потому что я ожидал, что validator будет вызван в любом случае, а default — если значение отсутствует или null. Но Vue так не работает.

После некоторых экспериментов я пришёл к такому решению:

props: {
  label: {
    type: String,
    required: false,
    validator(value) {
      // validator не вызывается, если передан null, но если вдруг вызовется — отсеиваем
      if (value === null) return false;
      return typeof value === 'string' && value.length > 0;
    },
    default: () => 'Default Label'
  }
},
computed: {
  safeLabel() {
    // если передали null — используем default
    return this.label === null ? this.$options.props.label.default() : this.label;
  }
}

Возможно это не идеально, но в свое время мне помогло.

→ Ссылка