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?
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
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With