Requirement is to provide an array of enums as an argument to define the return type interface. Based on these enum attributes Key.A
and or Key.B
the return type interface should contain A1
and or B1
with attribute keys (like enum keys) A
and or B
.
Pre-Setup looks like the following:
import { parse } from 'someWhere'; \\ will capitalize config first-lvl attributes
enum Key {
A = "a",
B = "b",
}
interface A1 {
x: string;
}
interface B1 {
y: string;
}
type FF = {
A: A1;
B: B1;
};
type Conf = <???>???;
const Fn = <E extends Key>(key: E[], config: unknown): Conf<E> => {
return parse.JSON(key, config) as Conf<E>;
};
Outcome should be that Fn
is called with some enum values and the returned interface only contains the corresponding attributes like:
const config = '{ "b": { "y": "some string" } }';
const res = Fn([Key.B], config);
console.log(res.B.y) // 'some string'
console.log(res.A.x) // Type Error: Property 'A' does not exist on type
based on that I tried the following:
type Conf<E extends Key> = {
[K in keyof typeof Key]: K extends E[keyof E] ? FF[K] : never;
};
const res = Fn([Key.B]);
With this implementation all attributes of Key exist in res
:
The second approach was to define Conf like
type Conf<E extends Key> = {
[K in E]: K extends E[keyof E] ? FF : never;
};
Only attribute b
exists in return interface but I couldn't find out how to index FF
to select the correct interface based on the enum => B1
. Additionally the resulting interface is res.b.
rather than res.B.
This is really tricky because
Key.B
,"B"
and"b"
are all different.If you are willing to rewrite your map
FF
such that it is keyed by the actual enum values"a"
and"b"
rather than the enum property names, it becomes trivially simple. You can just usePick<FF, E>
to get the return type.Otherwise I can't quite make sense of it either.