如何创建类型安全"Recursive"类型?



我想创建类型化的树结构,传递根节点和子节点模式。根据模式,我希望必需的属性是必需的,而不是可选的。然而,我的类型测试没有通过

type TypedTree<TRootSchema, TChildSchema = TRootSchema> =
{
[K in keyof TRootSchema]: TRootSchema[K]
} | {
[key: string]: TypedTree<TChildSchema>
}
const $typeTest = <T>(v: T) => v
// @ts-expect-error Required properies must be present
$typeTest<TypedTree<{ a: number }>>({ })
// 👆 It fails

我刚刚提出了一个可行的解决方案,需要显式传递可能的子节点键,然后类型就可以工作了。然而,我不想这样做,我希望打字脚本自己推断子键,或者其他任何事情,这样有问题的代码就可以工作了。

这是当前代码:


type Schema = Record<PropertyKey, unknown>
type SchemaTuple = [Schema, Schema]
type TypedTree2<
TSchema extends Schema | SchemaTuple,
TNodeKeys extends string = never,
_TInferredRootSchema_ extends Schema = TSchema extends SchemaTuple ? TSchema[0] : TSchema,
_TInferredChildSchema_ extends Schema = TSchema extends SchemaTuple ? TSchema[1] : TSchema
> = {
[K in keyof _TInferredRootSchema_]: _TInferredRootSchema_[K]
} & {
[K in TNodeKeys]?: TypedTree2<_TInferredChildSchema_, TNodeKeys>
}
$typeTest<TypedTree2<[{ a: number }, { a?: number }], 'foo' | 'bar' | 'baz'>>({
a: 1,
foo: {
bar: {
baz: {
foo: {
a: 10
}
}
}
}
})
// @ts-expect-error Required properties must be present
$typeTest<TypedTree2<{ a: number }>>({ })
$typeTest<TypedTree2<{ a: number }>>({ a: 1 })
$typeTest<TypedTree2<{ a: number }, 'a_2' | 'a_3'>>({
a: 1,
a_2: {
a: 2,
a_3: {
a: 3
}
}
})
$typeTest<TypedTree2<{ a: number }, 'a_2' | 'a_3'>>({
a: 2,
// @ts-expect-error Child node keys must satisfy second type parameter
unknown_key: { a: 3}
})

最新更新