Here is a possible solution that can make magic happen:
declare function magic<T extends string[]>(
...propertyNames: T
): Record<T[number], any>;
const result = magic("alpha", "bravo");
type ResultType = typeof result; // {alpha: any; bravo: any;}
Testing of ResultType:
const t1: ResultType = {
alpha: "foo",
bravo: 42,
wannaBe: 3 // error (OK)
};
You could then further restrict the any type in Record<T[number] any> with an additional type parameter, as any doesn't provide any useful typing.
declare function magic<T extends string[], R>(
...propertyNames: T
): Record<T[number], R>;
Some explanation
T[number] gives us all item values as union type. E.g.
type T = ["alpha", "bravo"]
type TItems = T[number] // "alpha" | "bravo"
Record makes sure, that we have all item values "alpha" | "bravo" as property keys.
- The tuple type can be inferred with help of generic rest parameters.
Playground