我正在尝试将Typescript映射类型用于简单的查询API。让我提供一个简化的例子:
interface IRoot {
user: IUser,
trips: Array<ITrip>
}
interface IUser {
name: string
}
interface ITrip {
prop: string
}
现在我可以构建一个这样的查询:
class Query<T, K extends keyof T> {
constructor(
private rootType: T,
private subQueries?: {[P in K]?: Query<T[P], any> }) { }
}
这适用于访问用户,但无法解决旅行数组的类型:
new Query(({} as IRoot), {
user: new Query(({} as IUser), ... /* This is a query on User and is accepted here */,
trips: new Query(({} as ITrip), ... /* This is a query on Trip and TS will complain, since T[P] is Array<ITrip> */
})
我可以将{[P in K]?: Query<T[P], any> }
扩展为接受T[P]
或T[P]
是一个数组,类型是什么?
答案 0 :(得分:0)
一个想法是创建一个IQuery
接口并创建两个实现,一个用于简单属性,另一个用于数组属性。 Query
将实现IQuery,ArrayQuery将实现IQuery。 IQuery
界面需要有一个使用T的方法或字段,以确保ArrayQuery<T>
和Query<T>
在结构上不兼容。
interface IQuery<T> {
// We need this method since the compiler checks structural compatibility we need to make implementations of IQuery<T> and IQuery<T[]> incompatible.
getRootType(): T;
}
class Query<T, K extends keyof T> implements IQuery<T>{
constructor(
private rootType: T,
private subQueries?: {[P in K]?: IQuery<T[P]> }) {
}
getRootType(): T {
return this.rootType;
}
}
class ArrayQuery<T, K extends keyof T> implements IQuery<T[]>{
constructor(private rootType: T,private subQueries?: {[P in K]?: Query<T[P], any> }) {
}
getRootType(): T[]{
return [this.rootType];
}
}
new Query(({} as IRoot), {
user: new Query(({} as IUser)),
trips: new ArrayQuery(({} as ITrip))
});