'Unique Set of an ordered key value pairs where the keys are only valid keys of another type

I'd like to create a type that takes a set (an array of key/value pairs with non-repeating keys).

// I have any given interface:
interface PersonRecord {
  id: string
  name: string
  age: number
}

// A type for order by direction
type SortDirection = "asc" | "desc"

I'd like to have some type/interface combination that would allow me to do something like this:

valid objects:

const orderSort: SortType<PersonRecord> = {
  0: { id: "asc" }
  1: { age: "desc" }
}

const personNameSort: SortType<PersonRecord> = {
  0: { name: "desc" }
}

invalid objects:

// only one key from PersonRecord at a time can be used in
// the values of the top level keys
const orderSort: SortType<PersonRecord> = {
  0: { id: "asc", age: "desc" }
}

// The top level keys must be numbers starting at zero and iterating
// every natural number by having no skips
const orderSort: SortType<PersonRecord> = {
  0: { id: "asc" }
  2: { age: "desc" }
}

// "xxx" is not a valid value because its not "asc" or "desc"
const personNameSort: SortType<PersonRecord> = {
  0: { name: "xxx" }
}

// test is not a key on PersonRecord
const personNameSort: SortType<PersonRecord> = {
  0: { test: "xxx" }
}

// keys from PersonRecord can only be used once
const orderSort: SortType<PersonRecord> = {
  0: { id: "asc" }
  1: { id: "desc" }
}

Here's an attempt at getting part of this piece working.

type SortType<T> = { [K in keyof Partial<T>]: SortDirection }

Some alternative solutions I'll accept: An array of key/value (value restricted to "asc" or "desc") and the keys cannot be reused:

// this would work...
const sortOrder = [{name: "asc"},{age: "desc"}]

// ...but this wouldn't because age was already included in the array.
// If there's not a clean way of adding this restriction, then I can
// write code to prevent this restriction programmatically I'm sure.
const sortOrder = [{name: "asc"},{age: "desc"},{age: "asc"}]

EDIT: So to help with this solution, let me explain exactly what this would be used for.

I want to make a function like this:

// orderArgs could be an array also so maybe something like
// SortType<T>[] and each item in the array is just something like:
// [{someAttribute: "asc"},{anotherAttribute: "desc"}]
// and you can only have an array of ONE key/value pair.
const orderBy = (orderArgs: SortType<T>) => {
  // a variable that orderBy has access to is called
  // 'records' which is of type: T[]
  return records.sort((last, next) => {
    // to determine which value to return (-1, 0 or 1)
    // I want to sort against the first item in orderArgs
    // if they are not equal, return 1 or -1.
    // However, if they are equal, go to the next item in
    // orderArgs and try sort based on that.
    // If you've gone through the whole list of orderArgs,
    // then last and next are truly equal, so return 0 here.
  }
}

EDIT 2: Here's a codesandbox proof of concept using @jcalz tips/help:

https://codesandbox.io/s/typed-data-storage-example-7n3kk4?file=/src/lib/useDataTable.ts



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source