type NotifyOptions = {
className: string
timeout?: null | number
} & ({ text: string } | { html: string })
export default function notify(options: NotifyOptions) {
if (options.text) {
console.info(options.text)
}
}
Property 'text' does not exist on type 'NotifyOptions'. Property 'text' does not exist on type '{ className: string; timeout?: number | null | undefined; } & { html: string; }'.(2339)
Почему говорится, что options.text не существует? Я думаю, он должен быть набран как string|undefined.






Эта площадка показывает рабочий пример, который допускает «размеченное объединение». Это работает так: он выделяет определенный тип с помощью проверки, которую Typescript действительно может использовать (буквальное равенство). См. дискриминируемые союзы.
type NotifyOptions = {
className: string;
timeout?: null | number;
} & ({
kind: "html";
html: string;
}|{
kind: "text";
text: string;
});
export default function notify(options: NotifyOptions) {
if (options.kind === "text") {
console.info(options.text);
}
else if (options.kind === "html") {
console.info(options.html);
}
}
К сожалению, как работает машинописный текст, вы можете ссылаться только на те свойства, которые существуют во всех случаях объединения. Следовательно, необходимо иметь свойство kind. Вы можете увидеть, когда jcalz научил меня этому на https://stackoverflow.com/a/65495776/2257198
Если в вашем случае действительно можно позволить себе не обращать внимания на систему типов (например, вас интересует только наличие свойства и возможность разыменовать его независимо от его типа), тогда наименьшее изменение исходного кода - использование Оператор in, который устраняет подобную ошибку компилятора.
export default function notify(options: NotifyOptions) {
if ("text" in options) {
console.info(options.text)
}
}
Вы можете пойти еще дальше по пути ввода javascript, опять же, если вам не нужны типы Typescript для вашего случая ...
export default function notify(options: NotifyOptions) {
if ("text" in options && typeof options.text === "string") {
console.info(options.text)
}
}
Машинопись позволит вам получить доступ только к свойствам, общим для каждого члена союза.
С другой стороны, это не позволит вам получить доступ к свойствам, определенным только в одном члене объединения.
Предположение о том, что элементы, существующие в одном члене объединения, не существуют в других элементах, на практике может не соответствовать действительности: они могут существовать, и тип свойства может быть другим.
Таким образом, предположение, что options.text является строкой или неопределенным, считается небезопасным.
Рассмотрим следующий пример:
const o = {
className: 'c1',
timeout: 3000,
html: 'ht',
text: 4
};
const opt: NotifyOptions = o;
Я создал NotifyOptions, где текст - это число.
В Typescript 3.2 появился Неединичные типы как дискриминанты объединения
TypeScript 3.2 makes narrowing easier by relaxing rules for what it considers a discriminant property. Common properties of unions are now considered discriminants as long as they contain some singleton type (e.g. a string literal, null, or undefined), and they contain no generics.
Ты можешь написать:
type NotifyOptions = {
className: string
timeout?: null | number
} & ({ text: string; html?: undefined; }
| { html: string; text?: undefined})
TypeScript позволяет вам получить доступ к свойствам и рассматривать их как дискриминанты объединения.
Кроме того, назначение константы o для NotifyOptions больше не разрешено.