Typescript 接口可以表达属性的共现约束吗

cef*_*efn 9 constraints typescript

在整体 Typescript 接口或类型定义中是否有标准模式来断言属性要么一起出现要么根本不出现?

例如,一个项目可能是有效的,如果它看起来像这样......

{
  id:"ljklkj",
  spellcheck:true,
  spellcheckModel:"byzantine",
}
Run Code Online (Sandbox Code Playgroud)

...或这个...

{
  id:"ljklkj",
}
Run Code Online (Sandbox Code Playgroud)

但是,如果任何一个拼写检查属性单独发生,则它是无效的。

{
  id:"ljklkj",
  spellcheckModel:"byzantine",
}
Run Code Online (Sandbox Code Playgroud)
{
  id:"ljklkj",
  spellcheck:true,
}
Run Code Online (Sandbox Code Playgroud)

整体式

当然,上面的简单情况可以通过创建一个 Data 和一个 SpellcheckData 类型或接口来解决。然而,在我的应用案例中,将有多个共现属性的“集群”。为每个共现组合定义一个新类型会导致类型爆炸,以表达这种情况。

出于这个原因,我将该解决方案称为“整体式”接口。当然,可能需要使用某种形式的组合来定义它。

我试过的

我试图在 Typescript 语言参考中找到这样的例子,但不知道该功能可能被称为什么(或者实际上,如果它是一个可以表达的功能),我很挣扎。属性可以是单独可选的,但我看不到表达共现的方式。

相关技术

此处讨论了 XML 数据验证的等效功能... https://www.w3.org/wiki/Co-occurrence_constraints

对于 JSON,我理解像 Schematron 和 Json Content Rules 这样的模式语言能够表达共同约束。

工作实例

如果我想像应用于 Solr 搜索引擎的 HTTP 参数集的共同约束情况的打字稿语法,它可能看起来像这样,表明您可以选择完全满足拼写或组参数,或者根本不-一个联合,其中每个类型都是可选的(由?表示)......

type SolrPassthru =
  SolrCoreParams & (
    SolrSpellParams? |
    SolrGroupParams?  
  )
Run Code Online (Sandbox Code Playgroud)

这与下面的示例形成对比,我认为这是正确的 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
Run Code Online (Sandbox Code Playgroud)

Les*_*iak 4

请尝试以下操作。看来它在正确的地方显示了错误。

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: ""};
Run Code Online (Sandbox Code Playgroud)

游乐场链接

更新

如果您更喜欢将类型作为元组传递,则可以使用以下实用程序:

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]>
Run Code Online (Sandbox Code Playgroud)

如果需要某些属性:

type Monolith = Data & CombinationOf<[Data, SpellCheckData, MoreData]>
Run Code Online (Sandbox Code Playgroud)