Enforce tuple in object is subset of another tuple in object with TypeScript?

  Kiến thức lập trình

I have a function that accepts an object with query arguments. A simplified example of query args is below. I want to ensure any values in sortBy are present in fields. I can check this at runtime but I am wondering if it is possible to do this with TypeScript.

const validQueryArgs = {
  fields: ['a', 'b', 'c'] as const,
  sortBy: ['a'] as const
};

const invalidQueryArgs = {
  fields: ['a', 'b', 'c'] as const,
  sortBy: ['d'] as const // ts error here would be great :) 
};

I know you can do something along the lines of this (Matt Pocock has a youtube short about this):

function createQueryArgs<T>({sortBy, fields}: { sortBy: NoInfer<T>, fields: T[] }): {fields: T[], sortBy: T } { 
    return {
      fields,
      sortBy
    }
}

const someArgs = createQueryArgs({
    sortBy: "c", // error here :thumbs-up:
    fields: ["a", "b"] as const
})

Is there any way I can do this without using a pass-through function?

I tried going down a conditional types road but hit a dead-end pretty quickly.

type CheckQueryArgs<T> = T extends { fields: infer Fields, sortBy: infer SortBy } ?
  SortBy extends Fields ?
  true :
  never :
  never

type CheckInvalid = CheckQueryArgs<typeof invalidQueryArgs> // never :thumbs-up:

type CheckValid = CheckQueryArgs<typeof validQueryArgs> // never :thumbs-down:

???? TypeScript playground

Thank you!

LEAVE A COMMENT