如何摆脱用于修复循环类型引用的接口

时间:2019-04-26 17:35:58

标签: typescript

我试图通过推断其元素类型来摆脱用作Array的接口。

type test(string | string[])[],但它应该是string[][]

我该如何解决?

type test = MyType<{ type: 'array'; items: { type: 'array'; items: { type: 'string' } } }>

type MyType<T> = T extends { type: 'string' }
  ? string
  : T extends { type: 'array' }
  ? UnpackMyArray<T extends { items: infer Items } ? MyArray<Items> : never>
  : never

interface MyArray<Declaration> extends Array<MyType<Declaration>> {}
type UnpackMyArray<T> = T extends Array<infer Item> ? Item[] : never

1 个答案:

答案 0 :(得分:1)

我希望我知道那里发生了什么,但我无法弄清楚。通过在接口中包装原本禁止的自引用条件类型来避免圆形类型检测器,然后立即将其拆开,这是一个技巧,并且可能很脆弱。我看到了针对other such tricks的警告;不确定最终的票价如何,但我会谨慎地依靠它。 (请注意,如果您只返回MyArray类型,这将不是问题...这是在此值得怀疑的其他解包方法。)

无论如何,我试图对其进行分析,但是即使我对代码进行了微小的更改,最终也使编译器感到困惑,整个输出结果都像any这样的类型。最后,我重新创建了您的逻辑并尽可能多地删除了conditional type inference,将其替换为property lookup types。类型推断比属性查找更具“魔力”,与查找相比,我对推断的结果信心不足。具体来说,我进行了以下更改:

  • 我将使用T extends {prop: infer P} ? P :

  • 代替T extends {prop: unknown} ? T['prop'] :
  • 我将使用T extends Array<infer L> ? L :而不是T extends Array<any> ? T[number] :

我也尽可能地折叠嵌套的条件类型(但我看到您也编辑了您的问题以执行此操作)

  • 我不是T extends {prop: infer P} ? P extends Q ? ... : never而是倒闭到T extends {prop: Q} ? ...

现在让我们看看你能得到什么:

type DeclarationType<D> = D extends { type: 'string' } ? string :
  (D extends { type: 'array', items: unknown } ? MyArray<D['items']> : never)[number][];

interface MyArray<D> extends Array<DeclarationType<D>> { }

type test = DeclarationType<{ 
  type: 'array'; items: { type: 'array'; items: { type: 'string' } } 
}>

这给了我type test = string[][],如您所愿。

Playground link


完美吗?可能不会。您可以期望它在新版本的TypeScript中继续工作吗?谁知道。从技术上讲,我是否使用2019年4月26日起在TS 3.3.3上运行的版本以及笔记本电脑上现在可用的任何TS版本(实际上是TS 3.5.0-dev.20190424)回答了您的问题?嗯,是的!

希望有所帮助;祝你好运。