There are many answers to this question on Stackoverflow (including this detailed one), but none of them worked for my situation, which is similar to the one posted here.
Problem
I have a function that takes an object. I want it to throw a Compilation Error (Typescript) if the passed object doesn't have exactly one key. e.g.
f({}); // Must error here, as it has less than one key!
f({ x: 5 });
f({ x: 5, y : 6 }); // Must error here, as it has more than one key!
Solution
Using the popular UnionToIntersection and IsUnion, I achieved it via the following utility function.
type SingleKey<T> = IsUnion<keyof T> extends true ? never : {} extends T ? never : T;
Full Code:
// From https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
// From: https://stackoverflow.com/a/53955431
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;
// Here we come!
type SingleKey<T> = IsUnion<keyof T> extends true ? never : {} extends T ? never : T;
// Usage:
function f<T extends Record<string, any>>(obj: SingleKey<T>) {
console.log({ obj });
}
f({}); // errors here!
f({ x: 5 });
f({ x: 5, y : 6 }); // errors here!
Playground Link
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…