#javascript #typescript #types
#javascript #typescript #типы
Вопрос:
итак, позвольте мне углубиться в пример:
type NodeOrMethod<T> =
| {
node?: Array<Filter<T>>;
method: Condition<T>;
}
| {
node: Array<Filter<T>>;
method?: Condition<T>;
};
interface BaseFilter {
label: string;
value?: string;
}
export type Filter<T> = BaseFilter amp; NodeOrMethod<T>;
По сути, я хочу сделать так, чтобы разработчик должен был либо включить node
, либо method
— что в настоящее время работает; однако я хочу сделать еще один шаг и сказать, что ЕСЛИ один из них присутствует, другого БЫТЬ НЕ МОЖЕТ. Поэтому, если они попытаются включить оба node
и method
в один и тот же объект, он будет жаловаться. Кто-нибудь делал что-то подобное раньше?
Комментарии:
1. Просто удалите необязательный тип?
2. @JonasWilms, похоже, это не работает. Если я добавлю как узел, так и метод, он не жалуется.
3. хм. Я всегда делаю
{ type: "one", stuff } | { type: "two", other }
, и это работает. Кажется, что тип объединения похож на «ИЛИ» и является исключительным только в том случае, если оба типа взаимно исключают друг друга.4. Что произойдет, если вы это сделаете
method: never
(к сожалению, я AFK, поэтому я не могу попробовать это сам)5. @JonasWilms Хм, я никогда не использовал
never
, я просто попробовал, и это кое-что испортило, но у меня могло быть странное форматирование.
Ответ №1:
Я бы, вероятно, использовал помеченные объединения (см. Соответствующий раздел документов) для того, что вы пытаетесь сделать, что-то вроде
type Node<T> = {
type: 'node',
node: Array<Filter<T>>;
}
type Method<T> = {
type: 'method',
method: Condition<T>;
}
type NodeOrMethod<T> = Node<T> | Method<T>;
cost a: NodeOrMethod<T> = { // valid
type: 'node',
node: [...]
}
cost b: NodeOrMethod<T> = { // valid
type: 'method',
method: ...
}
cost c: NodeOrMethod<T> = { // type error
type: 'method',
node: [...],
method: ...
}
<a rel="noreferrer noopener nofollow" href="https://www.typescriptlang.org/play/#src=type NodeT = {
type: ‘node’,
node: T
}
type MethodT = {
type: ‘method’,
method: T
}
type NodeOrMethod = NodeT | MethodT
const a: NodeOrMethod = {
type: ‘method’,
method: 123
}
const b: NodeOrMethod = {
type: ‘node’,
node: 123
}
const c: NodeOrMethod = {
type: ‘method’,
node: 123
}» rel=»nofollow noreferrer»>Пример
Комментарии:
1. Я чувствую, что это должно сработать для меня, но по какой-то причине это не так. Он по-прежнему позволяет присутствовать обоим
node
иmethod
. Он просто жалуется, когда ни того, ни другого нет. Конечно, у меня там нетtype
свойства.2. Я добавил ссылку на (упрощенную) демонстрационную версию playground
3. «У меня там нет свойства type», вот что делает его взаимоисключающим.
4. @JonasWilms хорошо, итак, мне нужно иметь подобное свойство, чтобы явно указать, какой из них там есть?
5. Да вроде того. Но я не знаю фактической семантики типа объединения, чтобы дать адекватный ответ (я все еще жду прибытия одного из этих ts goldbadgers), но, например,
{ exists: true, stuff } | { exists: false, other }
также будет работать
Ответ №2:
Философия узла / JS на самом деле так не работает. Объектам предоставляется разрешение иметь на них все, что они хотят, и потребляющий код обращает внимание только на то, что его волнует. Некоторые способы справиться с этим включают:
- Используйте заводские методы для обеспечения правильного создания экземпляров ваших объектов
- Имейте свойство «тип», которое указывает, смотреть ли на узел или метод
Все равно тип подозрительно перегружен двумя значениями. Я ожидаю, что есть другой доступный шаблон, который позволяет избежать этого. Если вы застряли в углу с кодом, который не является вашим, то один из вышеуказанных подходов должен работать нормально.
Комментарии:
1. Ваш первый абзац не имеет особого смысла, когда речь идет о Typescript, поскольку объекты имеют определенную форму. Фабричные методы помогли бы обеспечить определенную форму, но также и правильную типизацию. «тип подозрительно перегружен» ну что ж, в этом и заключается суть Typescript.
2. @JonasWilms Typescript не делает ничего, чтобы гарантировать, что у объекта нет свойств, которых я не ожидаю. Рассмотрите возможность расширения объекта или использования пересечения типов. Typescript стремится обеспечить доступность интерфейса, вот и все. Не то чтобы он не доступен. Он не делает этого, потому что пытаться бессмысленно и путает проблемы времени компиляции и выполнения.