Могут ли интерфейсы машинописного текста выражать ограничения совместного появления для свойств
Есть ли стандартный шаблон в монолитном интерфейсе машинописного текста или определениях типов для утверждения свойств, которые либо отображаются вместе, либо не отображаются вообще?
Например, предмет может быть действительным, если он выглядит так ...
{
id:"ljklkj",
spellcheck:true,
spellcheckModel:"byzantine",
}
...или это...
{
id:"ljklkj",
}
Однако было бы неверно, если бы любое из свойств проверки орфографии выполнялось изолированно.
{
id:"ljklkj",
spellcheckModel:"byzantine",
}
{
id:"ljklkj",
spellcheck:true,
}
Монолитный
Конечно, простой случай, описанный выше, можно решить, создав Data и SpellcheckData Type или Interface. В моем случае, однако, будет несколько «кластеров» сопутствующих свойств. Определение нового типа для каждой комбинации совпадения приведет к взрывному росту типов, чтобы выразить случай.
По этой причине я назвал это решение «монолитным» интерфейсом. Конечно, для его определения может потребоваться некоторая форма композиции.
Что я пробовал
Я пытался найти подобные примеры в справочнике по языку Typescript, но, не зная, как эта функция может вызываться (или действительно, если это функция, которая вообще может быть выражена), я борюсь. Свойства могут быть индивидуально необязательными, но я не вижу способа выразить совместное возникновение.
Связанные технологии
Здесь обсуждается эквивалентная функция проверки данных XML ... https://www.w3.org/wiki/Co-occurrence_constraints
Я понимаю, что для JSON языки схем, такие как Schematron и Json Content Rules, могут выражать сопутствующие ограничения.
Пример работы
Если бы я представил синтаксис машинописного текста для случая совместного ограничения, применяемого к наборам параметров HTTP для поисковой системы Solr, он мог бы выглядеть так, указывая на то, что вы можете выбрать полное соответствие параметрам Spell или Group или не полностью - объединение, в котором каждый тип является необязательным (обозначается знаком ? ) ...
type SolrPassthru =
SolrCoreParams & (
SolrSpellParams? |
SolrGroupParams?
)
Это контрастирует с приведенным ниже примером, который, как я считаю, является правильным TypeScript, но требует ВСЕ параметры из каждой группы параметров.
type SolrCoreParams = {
defType: SolrDefType,
boost: SolrBoostType,
}
type SolrSpellParams = {
spellcheck: "true" | "false",
"spellcheck.collate": "true" | "false",
"spellcheck.maxCollationTries": 1,
}
type SolrGroupParams = {
group: "true" | "false",
"group.limit": '4'
"group.sort": 'group_level asc,score desc,published desc,text_sort asc'
"group.main": 'true'
"group.field": 'group_uri'
}
type SolrPassthru =
SolrCoreParams &
SolrSpellParams &
SolrGroupParams
Ответы
Пожалуйста, попробуйте следующее. Кажется, он показывает ошибки в правильных местах.
type None<T> = {[K in keyof T]?: never}
type EitherOrBoth<T1, T2> = T1 & None<T2> | T2 & None<T1> | T1 & T2
interface Data {
id: string;
}
interface SpellCheckData {
spellcheck: boolean,
spellcheckModel: string,
}
// Two interfaces
var z1: EitherOrBoth<Data, SpellCheckData> = { id: "" };
var z2: EitherOrBoth<Data, SpellCheckData> = { spellcheck: true, spellcheckModel: 'm'};
var z3ERROR: EitherOrBoth<Data, SpellCheckData> = { spellcheck: true};
var z4: EitherOrBoth<Data, SpellCheckData> = { id: "", spellcheck: true, spellcheckModel: 'm'};
interface MoreData {
p1: string,
p2: string,
p3: string,
}
type Monolith = EitherOrBoth<Data, EitherOrBoth<SpellCheckData, MoreData>>
var x1: Monolith = { id: "" };
var x2: Monolith = { spellcheck: true, spellcheckModel: 'm'};
var x3ERROR: Monolith = { spellcheck: true};
var x4: Monolith = { id: "", spellcheck: true, spellcheckModel: 'm'};
var x5ERROR: Monolith = { p1: ""};
var x6ERROR: Monolith = { p1: "", p2: ""};
var x7: Monolith = { p1: "", p2: "", p3: ""};
var x8: Monolith = { id: "", p1: "", p2: "", p3: ""};
var x9ERROR: Monolith = { id: "", spellcheck: true, p1: "", p2: "", p3: ""};
var x10: Monolith = { id: "", spellcheck: true, spellcheckModel: 'm', p1: "", p2: "", p3: ""};
Ссылка на игровую площадку
Обновить
Если вы предпочитаете передавать типы в виде кортежа, вы можете использовать следующую утилиту:
type CombinationOf<T> = T extends [infer U1, infer U2] ? EitherOrBoth<U1, U2> :
T extends [infer U1, infer U2, infer U3] ? EitherOrBoth<U1, EitherOrBoth<U2, U3>> :
T extends [infer U1, infer U2, infer U3, infer U4] ? EitherOrBoth<U1, EitherOrBoth<U2, EitherOrBoth<U3, U4>>> :
never;
type Monolith = CombinationOf<[Data, SpellCheckData, MoreData]>
Если требуются какие-то свойства:
type Monolith = Data & CombinationOf<[Data, SpellCheckData, MoreData]>