1-3 `boolean` 与字面量类型

boolean 与字面量类型

摘要

总结 TypeScript 的 boolean、真假值转换及字面量类型,涵盖类型推断、拓宽、联合类型、as const 和判别联合。

1. boolean 基础

boolean 是 JavaScript 和 TypeScript 中表示逻辑状态的原始类型,只有两个可能值:truefalse

ts 复制代码
let enabled: boolean = true;

enabled = false;

常见使用场景包括:

  • 表示功能是否启用。
  • 表示用户是否登录。
  • 表示请求是否完成。
  • 表示条件判断的结果。
  • 控制分支、循环和界面状态。

1.1 类型推断

有明确初始值时,TypeScript 通常可以自动推断类型:

ts 复制代码
let enabled = true;

enabled = false;

这里的 enabled 被推断为 boolean,通常不需要重复写类型注解。

以下场景更适合显式声明类型:

  • 变量声明时没有初始值。
  • 希望限制变量只能接收特定字面量或联合类型。
  • 公共 API、对象模型或复杂返回值需要清楚表达契约。
ts 复制代码
let isReady: boolean;

isReady = true;

1.2 比较表达式返回 boolean

ts 复制代码
const age = 18;
const isAdult = age >= 18;
const isTeenager = age >= 13 && age < 18;

console.log(isAdult); // 输出: true
console.log(isTeenager); // 输出: false

===!==><>=<= 等比较运算符通常会产生布尔值。

1.3 逻辑运算符不一定返回 boolean

逻辑非 ! 一定返回布尔值,但 &&|| 返回的是参与运算的某个原始操作数,不一定是 boolean

ts 复制代码
const username = '小明';
const displayName = username || '匿名用户';
const result = username && 100;

console.log(displayName); // 输出: 小明
console.log(result); // 输出: 100
console.log(!username); // 输出: false

如果业务需要真正的布尔值,应使用 Boolean(value)!!value 明确转换。

官方文档TypeScript Handbook:The primitives stringnumber and boolean

2. booleanBoolean 的区别

2.1 小写 boolean

boolean 表示原始布尔值,是类型注解中应该使用的类型:

ts 复制代码
const enabled: boolean = true;

2.2 大写 Boolean

Boolean 是 JavaScript 的包装对象构造函数及相应对象类型。使用 new Boolean() 会创建对象,而不是原始布尔值:

ts 复制代码
const wrapped = new Boolean(false);

console.log(typeof wrapped); // 输出: object
console.log(wrapped.valueOf()); // 输出: false

包装对象本身是对象,所以即使它包装的是 false,放在条件中仍然属于真值:

ts 复制代码
const wrapped = new Boolean(false);

if (wrapped) {
  console.log('条件成立'); // 输出: 条件成立
}

因此,不要使用 new Boolean() 保存业务布尔状态,也不要在类型注解中使用大写 Boolean

ts 复制代码
let enabled: boolean = true;

// enabled = new Boolean(false);
// 错误:Boolean 对象不能赋给 boolean 原始类型

2.3 Boolean(value) 是布尔转换

不使用 new 时,Boolean(value) 会返回原始的 boolean

ts 复制代码
const enabled = Boolean(1);

console.log(enabled); // 输出: true
console.log(typeof enabled); // 输出: boolean

官方文档TypeScript Declaration Files:不要使用包装对象类型

3. 真值与假值

JavaScript 在条件判断中会把值转换为布尔值。这个规则称为 truthiness

3.1 常见假值

以下值转换为布尔值后是 false

ts 复制代码
console.log(Boolean(false)); // 输出: false
console.log(Boolean(0)); // 输出: false
console.log(Boolean(-0)); // 输出: false
console.log(Boolean(0n)); // 输出: false
console.log(Boolean('')); // 输出: false
console.log(Boolean(null)); // 输出: false
console.log(Boolean(undefined)); // 输出: false
console.log(Boolean(NaN)); // 输出: false

0n 需要支持 BigInt 的运行环境和编译目标。

3.2 常见真值

除少数假值外,大多数值都会转换为 true。特别注意,空数组和空对象也是真值:

ts 复制代码
console.log(Boolean('false')); // 输出: true
console.log(Boolean('0')); // 输出: true
console.log(Boolean([])); // 输出: true
console.log(Boolean({})); // 输出: true

字符串内容看起来像 false0,不代表它会转换为布尔值 false。只要字符串非空,它通常就是真值。

3.3 Boolean()!!

两种写法都能进行布尔转换:

ts 复制代码
const value: string | undefined = 'hello';

const convertedByFunction = Boolean(value);
const convertedByNegation = !!value;

通常:

  • Boolean(value) 可读性更直接,推断结果一般是 boolean
  • !!value 使用两次逻辑非完成转换;当表达式本身是编译器已知的固定真值或假值时,可能保留 truefalse 字面量类型。
ts 复制代码
const greeting = 'hello' as const;

const convertedByFunction = Boolean(greeting);
const convertedByNegation = !!greeting;

可以把推断结果理解为:

ts 复制代码
type ByFunction = boolean;
type ByNegation = true;

3.4 类型断言不会执行布尔转换

ts 复制代码
const value = 'false';

// const enabled = value as boolean;
// 错误思路:类型断言不会把字符串转换成布尔值

需要运行时转换时,应该真正调用 Boolean(value) 或使用 !!value。类型断言只影响编译阶段,不会改变实际数据。

4. Truthiness narrowing

TypeScript 会根据条件判断进行控制流分析,排除不可能的类型。

ts 复制代码
let value: string | null = Math.random() > 0.5 ? 'hello' : null;

if (value) {
  value.toUpperCase();
}

进入 if 分支后,TypeScript 知道 value 不再是 null;对于字符串,还意味着当前值不是空字符串。

4.1 Truthiness 检查可能合并多个业务状态

ts 复制代码
let count: number | undefined = 0;

if (count) {
  console.log('存在非零数量');
}

这里的 0 会和 undefined 一样进入假值分支。如果 0 是合法业务数据,就不应该只使用 truthiness 判断。

更精确的写法是显式检查:

ts 复制代码
if (count !== undefined) {
  console.log(count); // 输出: 0
}

4.2 显式比较布尔值

普通布尔变量通常直接判断即可:

ts 复制代码
const isReady = true;

if (isReady) {
  console.log('准备完成'); // 输出: 准备完成
}

当值不仅包含 boolean,或者需要明确区分 falseundefined 等状态时,可以使用严格比较:

ts 复制代码
let enabled: boolean | undefined = false;

if (enabled === false) {
  console.log('功能已明确关闭'); // 输出: 功能已明确关闭
}

官方文档TypeScript Handbook:Truthiness narrowing

5. 什么是字面量类型

字面量是直接写在代码中的具体值,例如 'success'200true。当具体值出现在类型位置时,就形成字面量类型。

ts 复制代码
let status: 'success' = 'success';
let code: 200 = 200;
let enabled: true = true;

字面量类型只允许一个确定的值:

ts 复制代码
let status: 'success' = 'success';

// status = 'failed';
// 错误:'failed' 不能赋给 'success'

可以把它理解为更具体的基础类型:

text 复制代码
'success' ⊂ string
200 ⊂ number
true ⊂ boolean

6. 常见字面量类型

6.1 字符串字面量类型

ts 复制代码
type Direction = 'left' | 'right';

let direction: Direction = 'left';
direction = 'right';

6.2 数字字面量类型

ts 复制代码
type HttpStatus = 200 | 400 | 404 | 500;

let status: HttpStatus = 200;
status = 404;

6.3 布尔字面量类型

ts 复制代码
let enabled: true = true;

// enabled = false;
// 错误:false 不能赋给 true

boolean 可以理解为 true | false 的联合:

ts 复制代码
type MyBoolean = true | false;

由于 true | falseboolean 表达的值域相同,普通布尔状态直接使用 boolean 即可。单独使用 truefalse 的价值在于表达更精确的对象分支或函数契约。

6.4 BigInt 字面量类型

ts 复制代码
type BinaryDigit = 0n | 1n;

let digit: BinaryDigit = 0n;
digit = 1n;

BigInt 字面量需要相应的 targetlib 和运行环境支持。

7. 字面量联合类型

单个字面量类型通常过于严格。实际开发更常见的做法是把多个允许值组合成联合类型。

ts 复制代码
type Theme = 'light' | 'dark' | 'system';

let theme: Theme = 'light';
theme = 'dark';

// theme = 'blue';
// 错误:'blue' 不属于 Theme

7.1 适合表示有限状态

ts 复制代码
type RequestStatus = 'idle' | 'loading' | 'success' | 'error';
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type Alignment = 'left' | 'center' | 'right';

字面量联合类型能够同时提供:

  • 编译阶段的合法值检查。
  • 编辑器自动补全。
  • 重构时的引用提示。
  • 比普通 string 更清晰的业务语义。

7.2 与枚举的区别

字符串字面量联合不会生成额外的 JavaScript 对象,适合只需要类型约束的场景。枚举具有自己的运行时表现和成员访问方式,是否使用应根据项目规范和运行时需求决定。

7.3 与普通联合类型组合

ts 复制代码
type Id = number | `user_${number}`;

let id: Id = 1001;
id = 'user_1001';

8. 模板字面量类型

模板字面量类型可以在类型层面组合字符串字面量,生成具有固定格式的字符串类型。

ts 复制代码
type EventName = 'click' | 'focus';
type HandlerName = `on${Capitalize<EventName>}`;

HandlerName 等价于:

ts 复制代码
type HandlerName = 'onClick' | 'onFocus';

也可以约束字符串格式:

ts 复制代码
type UserId = `user_${number}`;

const id: UserId = 'user_1001';

// const invalidId: UserId = 'order_1001';
// 错误:字符串格式不符合 UserId

模板字面量类型只在编译阶段约束字符串格式,不会在运行时验证外部输入。

9. 字面量类型的推断与拓宽

9.1 let 通常拓宽为基础类型

ts 复制代码
let status = 'success';
let code = 200;
let enabled = true;

由于变量允许重新赋值,推断结果通常是:

ts 复制代码
type Status = string;
type Code = number;
type Enabled = boolean;

9.2 基本类型的 const 通常保留字面量类型

ts 复制代码
const status = 'success';
const code = 200;
const enabled = true;

推断结果通常是:

ts 复制代码
type Status = 'success';
type Code = 200;
type Enabled = true;

9.3 const 对象的可写属性仍会拓宽

ts 复制代码
const config = {
  theme: 'dark',
  enabled: true,
};

const 只禁止 config 变量重新赋值,不禁止属性修改,因此通常推断为:

ts 复制代码
type Config = {
  theme: string;
  enabled: boolean;
};

以下修改是允许的:

ts 复制代码
config.theme = 'light';
config.enabled = false;

9.4 显式类型注解控制值域

ts 复制代码
type Theme = 'light' | 'dark';

const config: { theme: Theme; enabled: boolean } = {
  theme: 'dark',
  enabled: true,
};

config.theme 可以修改为 'light''dark',但不能变成任意字符串。

9.5 as const 保留字面量并添加只读约束

ts 复制代码
const config = {
  theme: 'dark',
  enabled: true,
} as const;

推断结果可以理解为:

ts 复制代码
type Config = {
  readonly theme: 'dark';
  readonly enabled: true;
};

as const 只影响 TypeScript 的推断,不会在运行时冻结对象。

9.6 satisfies 校验结构并保留自身推断

ts 复制代码
type ConfigShape = {
  theme: 'light' | 'dark';
  enabled: boolean;
};

const config = {
  theme: 'dark',
  enabled: true,
} satisfies ConfigShape;

satisfies 的主要作用是检查表达式是否满足目标结构,同时避免直接把变量整体标注为目标类型。具体属性是否保留为字面量类型,仍会受到目标类型和上下文推断影响。

官方文档TypeScript 2.1:Better inference for literal types

10. 使用布尔字面量构建判别联合

布尔字面量适合充当对象联合类型的判别字段,让不同状态携带不同数据。

ts 复制代码
type SuccessResult<T> = {
  success: true;
  data: T;
};

type FailureResult = {
  success: false;
  error: string;
};

type Result<T> = SuccessResult<T> | FailureResult;

使用判别字段后,TypeScript 可以自动收窄分支:

ts 复制代码
type User = {
  id: number;
  name: string;
};

declare const result: Result<User>;

if (result.success) {
  result.data.name;
} else {
  result.error;
}

相比下面这种结构,判别联合能够建立状态与数据之间的对应关系:

ts 复制代码
type LooseResult<T> = {
  success: boolean;
  data?: T;
  error?: string;
};

LooseResult<T> 无法仅凭 success 保证 dataerror 一定存在,而判别联合可以。

11. 布尔值与多状态建模

布尔值只适合表示两个互斥状态。当业务实际存在三个或更多状态时,不要强行使用多个布尔变量拼接状态。

容易产生无效组合的写法:

ts 复制代码
type RequestState = {
  isLoading: boolean;
  isSuccess: boolean;
  isError: boolean;
};

该类型允许三个字段同时为 true,但业务上可能不合理。

更清晰的写法是使用字面量联合:

ts 复制代码
type RequestStatus = 'idle' | 'loading' | 'success' | 'error';

type RequestState = {
  status: RequestStatus;
};

如果不同状态还携带不同数据,应进一步使用判别联合。

12. 常见误区

误区 1:'false' 会转换为 false

'false' 是非空字符串,转换结果是 true。解析表单、URL 或存储中的文本布尔值时,应显式比较字符串内容。

ts 复制代码
const value = 'false';
const enabled = value === 'true';

console.log(enabled); // 输出: false

误区 2:new Boolean(false) 是假值

它是包装对象,对象本身是真值。业务代码应使用原始 boolean

误区 3:&&|| 一定返回布尔值

它们返回操作数。需要布尔结果时,应明确转换或使用产生布尔值的比较表达式。

误区 4:truthiness 判断能区分所有业务状态

0''nullundefined 等都会进入假值分支。如果这些值含义不同,应使用严格比较或更明确的联合类型。

误区 5:const 对象属性会自动保留字面量类型

对象属性默认可写,因此通常会拓宽。需要只读字面量推断时,使用 as const;需要可写且值域受限时,使用显式联合类型。

误区 6:字面量类型越窄越好

过窄的类型会阻止正常修改。类型应表达真实业务约束,而不是一味追求最具体。

误区 7:类型约束会自动验证外部数据

TypeScript 类型在编译后会被移除。接口响应、表单值和本地存储数据仍需要运行时解析与校验。

13. 实际开发原则

  1. 类型注解使用小写 boolean,不要使用包装对象类型 Boolean
  2. 不使用 new Boolean() 保存业务状态。
  3. 进行布尔转换时使用 Boolean(value)!!value,不要使用类型断言代替转换。
  4. 0'' 等值具有独立业务含义时,使用显式比较,不要只依赖 truthiness。
  5. 只有两个互斥状态时使用 boolean;存在多个状态时使用字面量联合。
  6. 有限字符串、数字或布尔值域使用字面量联合,避免退化为宽泛的 stringnumber
  7. 需要建立状态与数据的对应关系时,使用判别联合。
  8. 需要保留对象字面量的精确类型时,根据可变性选择显式注解、as constsatisfies

14. 一句话总结

boolean 表示 truefalse,字面量类型把类型约束到具体值;通过联合类型和判别字段,可以准确表达有限状态及其数据关系。

相关推荐
光影少年1 小时前
react navite 长列表优化:FlatList / SectionList 原理与优化属性
前端·react native·react.js
cindershade1 小时前
鼠标 3D 倾斜卡片
前端
wordbaby1 小时前
从双端内卷到一库多端:基于 pnpm + Taro 4 + RNOH 鸿蒙的 Monorepo 跨端架构实战
前端·微信小程序·app
子兮曰1 小时前
DeepSeek Harness 架构深潜:一个把 Agent 运行时做成纯插件树的开源 Harness
前端·后端·deepseek
子兮曰2 小时前
AI Agent 完整入门指南:从 LLM 到生产落地的 30+ 个核心概念
前端·后端·agent
楚宝ovo2 小时前
新增一个 demo 子应用 - 微前端
前端
JarvanMo3 小时前
Dart 3.13:小版本,大动作
前端
纯粹的热爱3 小时前
Ubuntu 安装 Node.js 22.x(通过 NodeSource 官方源)
前端
Highcharts3 小时前
如何选择正确的图表:驱动理解和洞察力的三部分框架(第3部分)
前端·数据可视化