Reputation: 5824
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
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
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
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
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
Reputation: 5502
Use this
YourMethod(!!isEnabled);
'!!' is used for type casting to boolean
Upvotes: 5
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
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
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
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
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
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