打字稿映射类型或类型数组

时间:2017-08-28 09:29:36

标签: typescript

我正在尝试将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]是一个数组,类型是什么?

1 个答案:

答案 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)) 
});