Wanted to share my version of @jcalz solution that satisfied our ESLint extensive rules and my need of readability, hope it might helps:
/**
* Create an object type that can only have one key from a KeyUnion type with a specific ValueType
* @see https://stackoverflow.com/a/60873215
* @example
* const correctlyTypedArray : ObjectWithOnlyOneKeyFromUnion<"a" | "b", string> = [{a: "works"}, {b: "works too"}];
*/
export type ObjectWithOnlyOneKeyFromUnion<
KeyUnion extends string | number,
ValueType,
KeyUnionCopy extends string | number = KeyUnion,
> =
// make an object type with one key present
{
[Key in KeyUnion]: { [keyName in Key]: ValueType } & {
// make all other keys from KeyUnion as optional-and-never
[keyName in Exclude<KeyUnionCopy, Key>]?: never;
} extends infer ObjectType
? //merge all intersections into a single object type for type linter readability purposes
{ [keyName in keyof ObjectType]: ObjectType[keyName] }
: never;
}[KeyUnion];