Le interfacce Can Typescript esprimono vincoli di ricorrenza per le proprietà
Esiste un modello standard all'interno di un'interfaccia dattiloscritta monolitica o definizioni di tipo per affermare che le proprietà appaiono insieme o non appaiono affatto?
Ad esempio un articolo potrebbe essere valido se avesse questo aspetto ...
{
id:"ljklkj",
spellcheck:true,
spellcheckModel:"byzantine",
}
...o questo...
{
id:"ljklkj",
}
Tuttavia, non sarebbe valido se una delle proprietà del controllo ortografico si verificasse isolatamente.
{
id:"ljklkj",
spellcheckModel:"byzantine",
}
{
id:"ljklkj",
spellcheck:true,
}
Monolitico
Ovviamente il semplice caso sopra potrebbe essere risolto creando un Data e un SpellcheckData Type o Interface. Nel mio caso di domanda, tuttavia, ci sarà più di un "cluster" di proprietà ricorrenti. Definire un nuovo tipo per ogni combinazione di co-occorrenza porterebbe a un'esplosione di tipi per esprimere il caso.
Per questo motivo ho definito la soluzione un'interfaccia "monolitica". Ovviamente potrebbe essere necessario utilizzare una qualche forma di composizione per definirla.
Quello che ho provato
Ho provato a trovare esempi come questo all'interno del riferimento al linguaggio Typescript, ma senza sapere come potrebbe essere chiamata la funzione (o addirittura se è una caratteristica che può essere espressa del tutto), sto lottando. Le proprietà possono essere individualmente opzionali ma non riesco a vedere un modo per esprimere la co-occorrenza.
Tecnologie correlate
Una funzionalità equivalente per la convalida dei dati XML è discussa qui ... https://www.w3.org/wiki/Co-occurrence_constraints
Per JSON capisco che i linguaggi dello schema come Schematron e Json Content Rules sono in grado di esprimere co-vincoli.
Esempio funzionante
Se dovessi immaginare la sintassi del dattiloscritto per il caso di co-vincolo applicato ai set di parametri HTTP per il motore di ricerca Solr, potrebbe apparire così, indicando che potresti optare per soddisfare pienamente i parametri Spell o Group, o per niente - un'unione in cui ogni tipo è facoltativo (indicato dal ? ) ...
type SolrPassthru =
SolrCoreParams & (
SolrSpellParams? |
SolrGroupParams?
)
Ciò contrasta con l'esempio seguente, che credo sia corretto Typescript, ma richiede TUTTI i parametri da ogni gruppo di parametri.
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
Risposte
Si prega di provare quanto segue. Sembra che mostri gli errori nei posti corretti.
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: ""};
Collegamento al parco giochi
Aggiornare
Se preferisci passare i tipi come tupla, puoi utilizzare la seguente utilità:
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]>
Se sono richieste alcune proprietà:
type Monolith = Data & CombinationOf<[Data, SpellCheckData, MoreData]>