TypeScript递归条件映射类型

时间:2018-11-26 01:31:46

标签: typescript

我需要使用一个或某些测试函数来测试多个HTMLInputElement的每个值,并自动为每个复选框生成嵌套的复选框列表,条件表示为{{1} }:

Conditions

例如,如果我有:

type TestFunction = (value: string) => boolean
type TestFunctionObject = { [description: string]: Conditions }
type Conditions = TestFunction | TestFunctionObject

我得到一个标记为“由字母数字组成”的复选框。如果:

const conds1: Conditions = {
  "Consists of alphanumerics": /^[a-zA-Z0-9]$/.test
}

我不想要一个复选框,而只是对其进行验证。

自动生成已完成,没有任何问题。然后,我写了一个表示每个const conds2: Conditions = /^[a-zA-Z0-9]$/.test 的有效性的类型:

TestFunction

现在我在type Validity<C extends Conditions> = C extends TestFunction ? boolean : { [K in keyof C]: Validity<C[K]> } 上从TS收到了一个错误; playground here。它说C[K]。类型调节似乎不会将Type 'Conditions[K]' is not assignable to type 'TestFunctionObject'缩小到Conditions

我如何使它工作?

jcalz's answer 添加的内容:Playground with examples

1 个答案:

答案 0 :(得分:2)

我不认为编译器在条件类型的else子句中(在:之后)不会像通过控制流分析对值进行处理那样进行大量缩小。因此,虽然很明显在条件类型C extends TestFunction中,else子句中的C应该扩展TestFunctionObject,但编译器没有意识到。

但是编译器确实在then子句中(在?:之间)变窄,因此最简单的解决方法是添加另一个条件类型:

type Validity<C extends Conditions> = C extends TestFunction ? boolean
  : C extends TestFunctionObject ? { [K in keyof C]: Validity<C[K]> } : never

请注意,最后一个条件类型具有never作为else子句。这是带有条件类型的常见习语。有时,您知道无法达到else子句;并且在没有invalid type的情况下,never类型是一个很好的选择。

或者,由于开始时对then子句的处理不多,因此请翻转原始支票的子句:

type Validity<C extends Conditions> = C extends TestFunctionObject ?
  { [K in keyof C]: Validity<C[K]> } : boolean

应该都可以。希望能有所帮助;祝你好运!