我正在构建Typesafe formbuilder,它应该产生一系列可执行函数,如下所示:FormBuilder.Entity(Pair(DefaultStudent, {}), q =>
q.Select('name', 'gender')
.Children('courses', q => q.Select('code'))
一切正常,但是在q.select('code')
部分出现类型错误,指出类型实体与其他类型不兼容。
这是用于生成表单的代码:
interface FormSelector<T, U> {
entity: Pair<T, U>
Select: <K extends keyof T>(this: FormSelector<T, U>, ...properties: K[]) => FormSelector<Omit<T, K>, Pick<T, K> & U>
Children: <K extends Filter<T, Array<any>>, P extends keyof ArrayType<T[K]>>(
child: K,
q: (_: FormSelector<ArrayType<T[K]>, U>) => FormSelector<Omit<ArrayType<T[K]>, P>, Pick<ArrayType<T[K]>, P>>
) => FormSelector<Omit<T, K>, U & {[key in K]: Array<Pick<ArrayType<T[K]>, P>>}>
}
interface FormBuilder {
Entity: <T, U, K extends keyof T>(entity: Pair<T, U>, q: (_: FormSelector<T, U>) => FormSelector<Omit<T, K>, Pick<T, K> & U>) => Renderer<Pick<T, K> & U>
}
export let FormBuilder: FormBuilder = ({
Entity: function <T, U, K extends keyof T>(entity: Pair<T, U>, q: (_: FormSelector<T, U>) => FormSelector<Omit<T, K>, Pick<T, K> & U>): Renderer<Pick<T, K> & U> {
let x = q(FormSelector(entity)).entity.Second
return { data: x }
}
})
let FormSelector = <T, U>(e: Pair<T, U>): FormSelector<T, U> => ({
entity: e,
Select: function <K extends keyof T>(this: FormSelector<T, U>, ...properties: K[]): FormSelector<Omit<T, K>, Pick<T, K> & U> {
return null!
},
Children: function <K extends Filter<T, Array<any>>, P extends keyof ArrayType<T[K]>>(
child: K,
q: (_: FormSelector<ArrayType<T[K]>, U>) => FormSelector<Omit<ArrayType<T[K]>, P>, Pick<ArrayType<T[K]>, P>>
): FormSelector<Omit<T, K>, U & {[key in K]: Array<Pick<ArrayType<T[K]>, P>>}> {
return null!
}
})
// This will be responsible for rendering the form, can be pas to a react component
interface Renderer<T> {
data: T
}
以下是我使用的示例模型:
type Student = {
id: number
name: string
paid: boolean
gender: 'm' | 'v'
courses: Course[]
}
type Course = {
name: string
code: string
studypoint: number
}
const DefaultStudent: Student = {
id: 1,
gender: "m",
name: '',
paid: false,
courses: []
}
当我将FormSelector
中的实体类型从Pair<T, U>
更改为any
时,它将进行编译,但是我失去了类型安全性。任何人都可以解释我所得到的错误或有什么想法导致此错误?
答案 0 :(得分:0)
正如评论中所说,这个问题确实有很多事情发生,我修复了所有错误,然后看了出了什么问题。
FormBuilder
接口有一个方法Entity()
,女巫需要一个对象和一个lambda表达式,该表达式将a类型的FormSelector
转换为b类型的FormSelector
interface FormBuilder {
Entity: <T1, T2, TResult>(entity: T1, q: (_: FormSelector<T1, Unit>) => FormSelector<T2, TResult>) => Renderer<TResult>
}
这里出了问题,它与Select()
方法具有相同的签名,因此这意味着和功能链唯一可行的方法是Select()
。导致q => q.Select(...).Children(...)
不编译时出现类型错误。
此外,Children()
中的FormSelector
方法在lambda中不应将类型U
作为第二类型参数。 q
中Children
的类型必须是一个将嵌套对象的FormSelector从T
转换为FormSelector
的表达式,该interface FormSelector<T, U> {
entity: Pair<T, U>
Select: <K extends keyof T>(this: FormSelector<T, U>, ...properties: K[]) => FormSelector<Omit<T, K>, Pick<T, K> & U>
Children: <K extends Filter<T, Array<any>>, P extends keyof ArrayType<T[K]>>(
child: K,
q: (_: FormSelector<ArrayType<T[K]>, Unit>) => FormSelector<Omit<ArrayType<T[K]>, P>, Pick<ArrayType<T[K]>, P>>
) => FormSelector<Omit<T, K>, U & { [key in K]: Array<Pick<ArrayType<T[K]>, P>> }>
}
是嵌套对象的子集。
q
因此,更改Entity()
和Select()
中SELECT * FROM reporting_events WHERE (device_id = 51);
的两个表达式签名对我来说解决了这个问题。
我向可能对构建自定义类型安全框架感兴趣的人发布了此答案。也可以随意使用Playground
中的工作版本进行演奏