Reputation: 151
I have function where i accept array of string literals, and then infer type of second argument based on given array. As the simplest example let's just make second argument be one of array values
type Foo = (arr: any[], bar: typeof arr[number]) => any
As you can probably guess bar type is actually any since it is any[] in type declaration even if i provide something like
fooFunc([const1, const2], somethingElse)
Typescript will allow it. I understand that you cannot make const arguments at least for now, but is there any workaround to make this work?
Simple changing arr type to string[] won't work
const Codes = {
"NOT_FOUND": "404",
"FORBIDDEN": "403",
"OK": "200"
} as const
type Foo = (arr: string[], bar: typeof arr[number]) => any
const fooFunc: Foo = (arr, bar) => null;
fooFunc([Codes.FORBIDDEN, Codes.NOT_FOUND], "random string") //"random string" is string so it's completely ok
Changing arr type to Codes[] won't do the trick either, since it will allow Codes.OK which is not in our array.
Upvotes: 1
Views: 70
Reputation: 35512
Some good ol' typescript hacking will solve your issues.
const Codes = {
"NOT_FOUND": "404",
"FORBIDDEN": "403",
"OK": "200"
} as const;
type Foo = <T extends typeof Codes[keyof typeof Codes], K extends T>(arr: T[], bar: K) => any;
const fooFunc: Foo = (arr, bar) => null;
fooFunc([Codes.NOT_FOUND, Codes.FORBIDDEN], Codes.NOT_FOUND); // allowed
fooFunc([Codes.NOT_FOUND, Codes.FORBIDDEN], Codes.FORBIDDEN); // allowed
fooFunc([Codes.NOT_FOUND, Codes.FORBIDDEN], Codes.OK); // errors
fooFunc(["123"], "123"); // errors
See it in action here.
Upvotes: 2