这是 Github 上 Typescript 项目中发布的 issue 的后续内容。
Joe Calzaretta (@jcalz) 好心地为我的第一个递归条件类型问题提供了解决方案,但我现在面临另一个问题,函数参数变为
any
类型而不是预期类型。
以下是显示问题的代码摘录:
type ValidationContext<ValueType> = { value: ValueType }
type Constraint<ValueType, ConstraintType> =
ConstraintType | ((context: ValidationContext<ValueType>) => ConstraintType)
type StringType = string | null | undefined
type StringConstraints = {
required?: Constraint<StringType, boolean>,
length?: Constraint<StringType, number>
}
type StringSchema = readonly ["string", StringConstraints]
type ObjectType = object | null | undefined
type ObjectConstraints = { required?: Constraint<ObjectType, boolean> } | undefined
type ObjectSchema<T extends ObjectType> =
readonly ["object", ObjectConstraints, { [P in keyof T]: SchemaFor<T[P]> }]
type SchemaFor<T> =
[T] extends [StringType] ? StringSchema :
[T] extends [ObjectType] ? ObjectSchema<T> :
never
type AnySchema = StringSchema | ObjectSchema<ObjectType>
type ValidateSchema<T> =
T extends StringSchema ? StringSchema :
T extends readonly ["object", ObjectConstraints, infer S extends ObjectType] ?
readonly ["object", ObjectConstraints, { [K in keyof S]: ValidateSchema<S[K]> }] :
never
function validate<const T extends AnySchema>(schema: T & ValidateSchema<T>, value: any) {
return []
}
// Ok: context: ValidationContext<StringType>
validate(["string", { length: (context) => 1 }], null)
// Error: Parameter 'context' implicitly has an 'any' type
validate(["string", { required: (context) => true }], null)
// Error: Parameter 'context' implicitly has an 'any' type
validate(["object", { required: (context) => true }, {}], null)
// Ok:
// required: true | (true & ((context: ValidationContext<ObjectType>) => boolean))
// and
// required: true | (true & ((context: ValidationContext<StringType>) => boolean))
validate(["object", { required: true }, {
name: ["string", { required: true }],
}], null)
虽然在第一个
context
调用中正确推断了 validate
参数的类型(即:ValidationContext<StringType>
约束),但一旦我使用约束名称 length
,它就会变成 any
由 required
和 StringConstraints
分享。任何人都可以帮我获得预期的ObjectConstraints
类型吗?
这里有一个 typescript Playground 链接(简化版本,游乐场链接此处):
ValidationContext<...>
如果我将模式定义与对象一起使用(playground
),问题就消失了:
type StringSchema = ["string", { required?: (value: string) => boolean }]
type NumberSchema = ["number", { required?: (value: number) => boolean }]
type AnySchema = StringSchema | NumberSchema
function validate(schema: AnySchema) {
return schema[0]
}
// Error: Parameter 'value' implicitly has an 'any' type
validate(["string", { required: (value) => true }])
// Error: Parameter 'value' implicitly has an 'any' type
validate(["number", { required: (value) => true }])
所以我们可以非常确定这与元组的使用有关。
我应该修复 Github 上的错误吗?
如果我能理解如何设置 tsc 的自定义版本,我会尝试提供 PR。