Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript type of tuple member dependent on other

Tags:

typescript

I want to create a function which accepts many pairs of objects and keys of those objects and have the compiler enforce that. I currently have written the following:

declare function foo(...params: [any, string][]): void;

Which allows me to write something like

foo([a, "propOfA"], [b, "propOfB"]);

However, it also allows me to write

foo([a, "propofB"], [b, "propOfA"]);

This makes sense because the type of the second value is simply string. Can I use keyof to restrict the second value of every tuple to be a key of the first value of the same tuple?

like image 559
Panda Avatar asked Sep 07 '25 06:09

Panda


2 Answers

The code in @ExplosionPills's answer works if you only have one argument. If you want to support multiple tuple-valued arguments, each of which constrains the second element to be a key of the first, you can do it like this:

declare function foo<A extends any[]>(
  ...params: { [I in keyof A]: [A[I], keyof A[I]] }
): void;

Here we are using mapped tuples to represent params as a function of the A array, and inference from mapped types allows us to infer A from the first element of each tuple argument. Let's make sure it works:

const a = { a: 1 };
const b = { b: 2 };

// not allowed
foo([a, "b"]);
foo([b, "a"]);
foo([a, "a"], [b, "a"])

// okay
foo([a, "a"]);
foo([b, "b"]);
foo([a, "a"], [b, "b"]);

Looks good to me. Hope that helps; good luck!

Link to code

like image 169
jcalz Avatar answered Sep 09 '25 04:09

jcalz


You can do this using generics:

declare function foo<T>(...params: [T, keyof T][]): void;

Now, the type T will be inferred from the first array element of the argument you pass in.

const a = { a: 1 }
const b = { b: 2 }

// not allowed
foo([a, 'b']);
foo([b, 'a']);

// okay
foo([a, 'a']);
foo([b, 'b']);

Note that if you use multiple arguments, e.g. foo([a, 'a'], [b, 'b']) a and b will have to be of the same type (or compatible types).

like image 45
Explosion Pills Avatar answered Sep 09 '25 04:09

Explosion Pills