skip to Main Content
export type ReadPayloadT<T extends keyof ERPTypes> = {
  model: T
  ids: number[]
  fields?: (keyof ERPTypes[T])[]
  with_context?: string
  with_company?: number
}

export const readQuery = async <T extends keyof ERPTypes>(
  payload: ReadPayloadT<T>
): Promise<
  ReadPayloadT<T> extends { fields: (keyof ERPTypes[T])[] }
    ? Pick<ERPTypes[T], keyof ERPTypes[T]>[]
    : ERPTypes[T][]
> => {
  if (!token) {
    let { data } = await auth()
    token = data.access_token
  }
  return axios
    .post(process.env['E_URL'] + '/api/v2/read', payload, {
      headers: {
        DATABASE: process.env['E_DB']!,
        Authorization: 'Bearer ' + token,
      },
    })
    .then((res) => res.data)
}

readQuery({
  ids: [234],
  model: 'res.company',
  fields: ['vat'],
}).then((res) => {
  res[0].vat_check_vies
})

I have this function "readQuery"

The return type should be ERPTypes[T]
If i provide fields then the return type should only contain the type of the keys i provided inside fields

In this case res[0] should only contain res[0].vat and nothing else.
If i dont provide fields then res[0] should provide every key of ERPTypes[T]

So basically, the backend returns me the object with only the propertys of fields. If i provide nothing then it returns me the whole object.

I was thinking about overloads, but i want to ask if there is a better idea?

How do i do this?

EDIT:

export type ReadPayloadWithFieldsT<T extends keyof ERPTypes> = {
  model: T
  ids: number[]
  fields: (keyof ERPTypes[T])[]
  with_context?: string
  with_company?: number
}
export type ReadPayloadWithoutFieldsT<T extends keyof ERPTypes> = {
  model: T
  ids: number[]
  with_context?: string
  with_company?: number
}

export type ReadQueryOverloadT = {
  <T extends keyof ERPTypes>(payload: ReadPayloadWithFieldsT<T>): Promise<
    Pick<ERPTypes[T], keyof ERPTypes[T]>
  >
  <T extends keyof ERPTypes>(payload: ReadPayloadWithoutFieldsT<T>): Promise<
    ERPTypes[T][]
  >
}

export const readQuery: ReadQueryOverloadT = async (payload) => {
  if (!token) {
    let { data } = await auth()
    token = data.access_token
  }
  return axios
    .post(process.env['E_URL'] + '/api/v2/read', payload, {
      headers: {
        DATABASE: process.env['E_DB']!,
        Authorization: 'Bearer ' + token,
      },
    })
    .then((res) => res.data)
}

readQuery({
  ids: [234],
  model: 'res.company',
}).then((res) => {
  res[0]
})

I have made it so far.
My problem is now, how do i pick those keys i used in fields?

 Pick<ERPTypes[T], keyof ERPTypes[T]>

With this solution it picks nothing.
In this example it should only pick vat because i wrote it.

2

Answers


  1. Chosen as BEST ANSWER
    export type ReadPayloadWithFieldsT<
      T extends keyof ERPTypes,
      F extends keyof ERPTypes[T]
    > = {
      model: T
      ids: number[]
      fields: F[]
      with_context?: string
      with_company?: number
    }
    export type ReadPayloadWithoutFieldsT<T extends keyof ERPTypes> = {
      model: T
      ids: number[]
      with_context?: string
      with_company?: number
    }
    
    export type ReadQueryOverloadT = {
      <T extends keyof ERPTypes, F extends keyof ERPTypes[T]>(
        payload: ReadPayloadWithFieldsT<T, F>
      ): Promise<Pick<ERPTypes[T], F>[]>
      <T extends keyof ERPTypes>(payload: ReadPayloadWithoutFieldsT<T>): Promise<
        ERPTypes[T][]
      >
    }
    
    export const readQuery: ReadQueryOverloadT = async (payload) => {
      if (!token) {
        let { data } = await auth()
        token = data.access_token
      }
      return axios
        .post(process.env['E_URL'] + '/api/v2/read', payload, {
          headers: {
            DATABASE: process.env['E_DB']!,
            Authorization: 'Bearer ' + token,
          },
        })
        .then((res) => res.data)
    }
    
    readQuery({
      ids: [234],
      model: 'res.company',
      fields: ['vat'],
    }).then((res) => {
      res[0].vat //<-- this has only VAT
    })
    

    I have a solution!


  2. One way is to use conditional types in the return type of your function, such as Promise<ReadPayloadT<T> extends { fields: (keyof ERPTypes[T])[] } ? Pick<ERPTypes[T], keyof ERPTypes[T]>[] : ERPTypes[T][]>. However, this might require you to use type assertions in your function body, such as return axios.post(…) as any.

    Another way is to use overloads instead of conditional types. You can define multiple function signatures for different parameter types and return types, such as:

    export function readQuery<T extends keyof ERPTypes>(payload: ReadPayloadWithFieldsT<T>): Promise<Pick<ERPTypes[T], keyof ERPTypes[T]>[]>;
    export function readQuery<T extends keyof ERPTypes>(payload: ReadPayloadWithoutFieldsT<T>): Promise<ERPTypes[T][]>;
    export function readQuery<T extends keyof ERPTypes>(payload: ReadPayloadT<T>): Promise<any> {
      // your implementation here
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search