TypeScript转换为布尔类型

101

在Typescript中我可以这样做:

var xxx : some_type;

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

无论xxx的类型是什么,它都将被视为布尔值。

我想在函数参数中做同样的事情。我有这个函数:

function foo(b : boolean) { ... }
我希望能够调用foo(xxx)并使xxx被视为布尔类型,而不管它的原始类型是什么。但是TypeScript不允许这样做。
我尝试了这个:
foo(<boolean>xxx);
但 TypeScript 也不会允许这样做。 我可以这样做:
foo(xxx ? true : false);

但那似乎有点傻。有更好的方法吗?


2
你想要做的是基于真值和假值逻辑的宽松类型。TypeScript 的主要目的是为 JavaScript 添加静态类型,恰好是为了防止你进行宽松类型。因此你实质上是在尝试做 TypeScript 所设计的预防措施。我建议分析一下你传递的参数可以是什么类型,并加入重载定义。 - Stephen Chung
3
问题在于一致性。如果TypeScript允许我在if (xxx)中使用非布尔值,那么我在其他布尔上下文中也应该可以使用非布尔值。在我看来,要么两者都允许,要么都禁止。 - oz1cz
1
Typescript 对此并不“开心”,但 Typescript 具有向后兼容 JavaScript 的能力。将 "if" 视为以 Any 类型参数输入的函数,这也是三元表达式可以工作的原因。TS 不鼓励这种草率的类型定义,但为了向后兼容而容忍它。下面使用 !! 的答案之所以有效,是因为非运算符的输入是 Any 类型,输出是布尔类型。 - Peter Wone
10个回答

133
你可以使用双感叹号技巧,Typescript允许并且在JavaScript中也可以正常工作。
foo(!!xxx);

或者将其转换为 any

foo(<any>xxx);

8
这不起作用:console.log("!!'false': ",!!'false') 给我返回了 !!'false': true。 - Toolkit
30
在JavaScript中,字符串'false'是一种“truthy”(https://developer.mozilla.org/en-US/docs/Glossary/Truthy),因此它可以正常工作。 - Knaģis
7
在JavaScript中(通过扩展TypeScript),只有当字符串为空字符串(或未定义)时,它才为假。 - daotoad
1
@Knaģis,!!xxx 是什么意思? - Roxy'Pro
2
@Roxy'Pro !!xxx 字面意思是“非非 xxx”,因此它是一个双重否定,有效地将表达式“xxx”转换为布尔值。 - Nathan Arthur
显示剩余3条评论

18

这是我的解决方案,用于"typescript": "^3.3.3"

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

export { toBool };

单元测试:

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();
    });
  });
});

单元测试结果:

 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

不好的答案:isAdd 总是为真... (这里是TS 2.9.1) - Mike Aski
valueOf() 是一个无操作,因为 Boolean(x) 总是返回一个布尔值。 - Leland

10
使用 TypeScript 最明显的方法是使用 Boolean 构造函数:
Boolean(someVal);

在你的情况下,它将是:
foo(Boolean(xxx));

请注意,构造函数是不需要使用 "new" 关键字的。因为如果添加它,将会创建一个新的布尔对象而不是对值进行转换:
Boolean(false) == false 

但是

new Boolean(false) == true

因为它是一个对象


谢谢,@fs_dm,这比!!xxx清楚多了。 - oz1cz

8
使用TypeScript 2.0.2,您可以这样做:
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!'

8

虽然无法直接将数字转换为布尔值,但可以将其转换为包装类Boolean,然后立即取消包装。例如:

foo(<boolean><Boolean>xxx);

虽然有些笨重,但它避免了将类型强制转换为<any>时的类型擦除。相较于使用!!方法(在转译后的js代码中更加清晰易懂),它也可以说更加简明易读。


1
有帮助的答案,谢谢。但我想补充一点,我在许多 JavaScript 和 TypeScript 的代码中看到(并使用)了 !! 的方法,所以我不认为“模糊”的论点非常可靠。我个人认为它比双重转换更易读。 - Iravanchi
4
双重类型转换写起来很长,阅读起来也很麻烦,而使用 !! 则只会对真正初级的 JavaScript 开发人员有些晦涩。 - Teodor Sandu

5

使用这个

YourMethod(!!isEnabled);

'!!' 用于将值转换为布尔类型。

请考虑在您的代码中添加一些解释说明。 - L. F.

4

这里有一个简单的函数,可以处理大多数情况,包括将布尔值作为输入处理(以防万一):

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; 
}

以下是一个简单的测试示例:

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);
        });
    })
});

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

然而,在代码中每次调用foo时,您可能会重复使用双感叹号,因此更好的解决方案是将强制转换为布尔值移至函数内部DRY
foo(xxx);

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

如上所述:非空字符串不会神奇地转换为它们的布尔等效形式 if ("false") { console.info("I'm not false"); } // 这将记录 - Gyuri
@Gyuri 这是真的,但JavaScript也是如此,所以我不太明白问题在哪里。"false"是一个真值 - undefined

0
不像!!foo那样简洁,但它能工作并且很明显。
(foo as any) as boolean

为什么TypeScript不直接支持'as boolean'或者将truthy转换为true,falsey转换为false,这是一个谜。我认为TypeScript应该支持以下一种或两种方式:
foo as boolean
<boolean>foo

那种类型强制转换非常明确,我不认为转译器需要抱怨我可能没有打算使用'as boolean'。

-1

如果(xxx) {...} //当 xxx 不是 undefined 或 null 时,读作 TRUE 如果(!xxx) {...} //当 xxx 是 undefined 或 null 时,读作 TRUE

对于像 'true' 或 'false' 这样的字符串: xxx.toLowerCase().trim() === 'true' ? true : false

因此:

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;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接