Home > Enterprise >  Why doesn't my TS Boolean override work for `any` or `unknown`?
Why doesn't my TS Boolean override work for `any` or `unknown`?

Time:07-12

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.

  • Related