2

Let's say we have a generic interface

interface CompareOp<T>{
  a: T;
  b: T;
  cmp: (v1: T, v2: T) => number;
}

I'm looking for a way to create a type for an array of CompareOp of any type. For example:

// valid, each compare function receives the type of its fields
[
  {a: 1, b:1, cmp: (v1: number, v2: number) => v1 - v2},
  {a: 'a', b: 'b', cmp: (v1: string, v2: string) => v1.localCompare(v2)}
]
// invalid, compare function does not match fields
[
  {a: 1, b:1, cmp: (v1: string, v2: string) => v1.localCompare(v2),
  {a: 'a', b: 'b', cmp: (v1: number, v2: number) => v1 - v2}
]

Is there a way to express the type of this array in TypeScript?

1
  • Could you provide an example of which result you're waiting for ? Would you like the second array to be considered as an array of CompareOp ? The issue happening in your second array is that the type used in your operation does not satisfy the generic declaration of your interface: If a & b are of type T, so should be the ones used in your cmp as well. If you want them to possibly be different, then your interface should be CompareOp<T, U>{ a: T; b: T; cmp: (v1: U, v2: U) => number; }. Is that what you're searchinng for ? Commented Feb 9, 2023 at 13:12

1 Answer 1

2

You can't create a stand-alone type that performs individual validation of array elements.

What you can do is to utilize the inference of a generic function and use a reverse mapped type to validate each array element against CompareOp.

interface CompareOp<T> {
  a: T;
  b: T;
  cmp: (v1: T, v2: T) => number;
}

function compareOp<T extends any[]>(
  arr: [...{ [K in keyof T]: CompareOp<T[K]> }]
) {}

compareOp([
  { a: 1, b: 1, cmp: (v1: number, v2: number) => v1 - v2 },
  { a: "a", b: "b", cmp: (v1: string, v2: string) => v1.localeCompare(v2) },
]);

compareOp([
  { a: 1, b: 1, cmp: (v1: string, v2: string) => v1.localeCompare(v2) },
//              ~~~ Type 'number' is not assignable to type 'string'
  { a: "a", b: "b", cmp: (v1: number, v2: number) => v1 - v2 },
//                  ~~~ Type 'string' is not assignable to type 'number'.
]);

Playground

Sign up to request clarification or add additional context in comments.

4 Comments

What does the spread opreator do there?
The compiler will infer T as an array type if we don't use a variadic tuple here. But we need a tuple type for T so that each element in the array gets its own type element in T
This seems exactly like what i need!, But cant seem to find anything regarding the term "reverse mapped type" online, could you exaplain how it works or link something?
@Plargato - I have seen no official documentation which uses the term "reverse mapped type". I have seen it mostly used by TypeScript-contributors and in the source code of the compiler itself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.