oz1cz
oz1cz

Reputation: 5824

Typescript conversion to boolean

In Typescript I can do this:

var xxx : some_type;

if (xxx)
    foo();
else
    bar();

Here xxx will be treated as a boolean, regardless of its type.

I would like to do the same thing in a function argument. I have this function:

function foo(b : boolean) { ... }

I want to be able to call foo(xxx) and have xxx treated as a boolean, regardless of its type. But Typescript won't allow that.

I tried this:

foo(<boolean>xxx);

but that Typescript won't allow that either.

I can do this:

foo(xxx ? true : false);

But that seems a bit silly. Is there a better way to do it?

Upvotes: 107

Views: 179550

Answers (11)

Knaģis
Knaģis

Reputation: 21485

You can use double exclamation sign trick which Typescript does allow and which works fine in JavaScript:

foo(!!xxx);

Alternatively, cast it to any

foo(<any>xxx);
foo(xxx as any);

Upvotes: 140

Mayur Nandane
Mayur Nandane

Reputation: 317

const booleanOfsomeVal = someVal == "1" || someVal == "true";

This should work in typescript & javascript both

considering someVal could have possible values

0/1/"0"/"1"/true/false/"true"/"false"/undefined/null/NaN

Upvotes: 0

Mark_Sagecy
Mark_Sagecy

Reputation: 340

Not as concise as !!foo, but it works and is pretty obvious.

(foo as any) as boolean

It is a mystery why typescript doesn't simply support 'as boolean' or to convert truthy to true and falsey to false. I believe typescript should support one or the both of the following:

foo as boolean
<boolean>foo

That type coercion is pretty explicit, and I don't think the transpiler needs to complain that maybe I didn't intend 'as boolean.'

Upvotes: 0

fs_dm
fs_dm

Reputation: 401

The most obvious way to do this with typescript is to use a Boolean constructor:

Boolean(someVal);

in your case it will be:

foo(Boolean(xxx));

please note that the constructor is used without the "new" keyword. Because if you add it, you will create a new boolean object instead of casting the value:

Boolean(false) == false 

but

new Boolean(false) == true

because it is an object

Upvotes: 10

Abdus Salam Azad
Abdus Salam Azad

Reputation: 5502

Use this

YourMethod(!!isEnabled);

'!!' is used for type casting to boolean

Upvotes: 5

Lin Du
Lin Du

Reputation: 102257

Here is my solution for "typescript": "^3.3.3":

function toBool(a: any) {
  return Boolean(a).valueOf();
}

export { toBool };

unit test:

import { toBool } from '../../utils/bool';

describe('bool', () => {
  describe('#toBool', () => {
    it('should convert string to boolean', () => {
      expect(toBool('false')).toBeTruthy();
      expect(toBool('')).toBeFalsy();
    });
    it('should convert number to boolean', () => {
      expect(toBool(1)).toBeTruthy();
      expect(toBool(0)).toBeFalsy();
      expect(toBool(-1)).toBeTruthy();
      expect(toBool(Infinity)).toBeTruthy();
      expect(toBool(-Infinity)).toBeTruthy();
    });
    it('should convert null to boolean', () => {
      expect(toBool(null)).toBeFalsy();
    });
    it('should convert undefined to boolean', () => {
      expect(toBool(undefined)).toBeFalsy();
    });
    it('should convert NaN to boolean', () => {
      expect(toBool(NaN)).toBeFalsy();
    });
    it('should convert object to boolean', () => {
      expect(toBool({})).toBeTruthy();
    });
    it('should convert array to boolean', () => {
      expect(toBool([])).toBeTruthy();
    });
  });
});

unit test results:

 PASS  src/__tests__/utils/bool.spec.ts
  bool
    #toBool
      ✓ should convert string to boolean (3ms)
      ✓ should convert number to boolean (1ms)
      ✓ should convert null to boolean (1ms)
      ✓ should convert undefined to boolean
      ✓ should convert NaN to boolean (1ms)
      ✓ should convert object to boolean (1ms)
      ✓ should convert array to boolean

Test Suites: 1 passed, 1 total
Tests:       7 passed, 7 total
Snapshots:   0 total
Time:        3.79s, estimated 4s

Upvotes: 18

asusfan
asusfan

Reputation: 41

Here's a simple function that will handle most scenarios, including handling booleans as an input (just in case):

type Falsey = undefined | null;
const parseBoolean = (val: string | boolean | number | Falsey): boolean => {
  const s = val && val.toString().toLowerCase().trim();
  if (s == 'true' || s == '1')
    return true;
  return false; 
}

And here's a jest test to go with it:

describe('Boolean Parser', () => {
    [
        { val: 'true', expected: true },
        { val: 'false', expected: false },
        { val: 'True', expected: true },
        { val: 'False', expected: false },
        { val: 'TRUE', expected: true },
        { val: 'FALSE', expected: false },
        { val: '', expected: false },
        { val: '1', expected: true },
        { val: '0', expected: false },
        { val: false, expected: false },
        { val: true, expected: true },
        { val: undefined, expected: false },
        { val: null, expected: false },
        { val: 0, expected: false },
        { val: 1, expected: true },
        { val: 111, expected: false }
    ].forEach(args => {
        it(`should parse ${args.val} to boolean`, () => {
            expect(parseBoolean(args.val)).toBe(args.expected);
        });
    })
});

Upvotes: 4

Lubo
Lubo

Reputation: 9

if(xxx) {...} //read as TRUE if xxx is NOT undefined or null if(!xxx) {...} //read as TRUE if xxx IS undefined or null

For a string like 'true' or 'false': xxx.toLowerCase().trim() === 'true' ? true : false

so:

var zzz = 'true'; //string
var yyy = [];  //array

...

if(zzz.toLowerCase().trim() === 'true') { ... }  // quick string conversion

...

if(yyy ? true : false) { ... }  // quick any conversion - it's TRUE if it's not null or undefined

...

// in a catch-all function

if(toBoolean(zzz)) { ... }
if(toBoolean(yyy)) { ... }


toBoolean(xxx: any): boolean {
  if(xxx) {
    const xStr = xxx.toString().toLowerCase().trim();
    if(xStr === 'true' || x === 'false') {
      return xStr === 'true' ? true : false;
    } else {
      return xxx ? true : false;
    }
  } else {
    return false;
  }
}

Upvotes: -1

Craft Master
Craft Master

Reputation: 69

foo(!!xxx); // This is the common way of coercing variable to booleans.
// Or less pretty
foo(xxx && true); // Same as foo(xxx || false)

However, you will probably end up duplicating the double bang everytime you invoke foo in your code, so a better solution is to move the coerce to boolean inside the function DRY

foo(xxx);

foo(b: any){
  const _b = !!b;
  // Do foo with _b ...
}
  /*** OR ***/
foo(b: any){
  if(b){
    // Do foo ...
  }
}

Upvotes: 3

benlambert
benlambert

Reputation: 111

With TypeScript 2.0.2 you can do this:

type Falsey = '' | 0 | false | null | undefined;

function eatFruit(fruit: string | Falsey) { 
  if (fruit) {
    alert(`Ate ${fruit}`);
  } else {
    alert('No fruit to eat!');
  }
}

const fruits = ['apple', 'banana', 'pear'];
eatFruit(fruits[0]); // alerts 'Ate apple'
eatFruit(fruits[1]); // alerts 'Ate banana'
eatFruit(fruits[2]); // alerts 'Ate pear'
eatFruit(fruits[3]); // alerts 'No fruit to eat!'

const bestBeforeDay = 12;
let day = 11;
eatFruit(day < bestBeforeDay && 'peach'); // alerts 'Ate peach'
day += 1;
eatFruit(day < bestBeforeDay && 'peach'); // alerts 'No fruit to eat!'

let numMangos = 1;
eatFruit(numMangos && 'mango'); // alerts 'Ate Mango'
numMangos -= 1;
eatFruit(numMangos && 'mango'); // alerts 'No fruit to eat!'

Upvotes: 8

dug
dug

Reputation: 2335

While you can't cast a number directly to a boolean, you can cast it to the wrapper Boolean class and immediately unwrap it. For example:

foo(<boolean><Boolean>xxx);

While clumsy, it avoids the type erasure of casting to <any>. It's also arguably less obscure & more readable than the !! approach (certainly so in the transpiled js code).

Upvotes: 8

Related Questions