I want Boolean(truthy)
to yield a type of true
instead of Boolean
, and likewise for falsy => false
So I wrote this:
interface BooleanConstructor {
<T extends false | 0 | '' | null | undefined>(value?: T): false;
<T extends Record<any, any> | string | number | true>(value?: T): true;
<T>(value?: T): boolean;
}
Works great, except for any
and unknown
. Any ideas?
const A = Boolean(42 as any); // false ??
const B = Boolean(42 as unknown); // boolean
const A2 = Boolean(''); // false
const B2 = Boolean(0); // false
const C = Boolean(42); // true
const D = Boolean('hello'); // true
const E = Boolean(true); // true
const F = Boolean(false); // false
const G = Boolean(null); // false
const H = Boolean(undefined); // false
const I = Boolean([]); // true
const J = Boolean({}); // true
ts playground with a local function instead, but same same.
CodePudding user response:
Boolean(42 as any)
can match either overload (because any
matches anything), so it will resolve whichever comes first. If you swap your overload order, you'll get true
instead of false
here.
For a hack that might work, see this playground. Basically, you need a new overload where T
looks for a type that won't match any of your other overloads to go first, something like:
interface BooleanContstructor {
<T extends { [`@hopefully-this-long-string-will-never-be-used-as-a-property`]: {} }>(value: T): boolean
// ...
Or, do this.