跳到主要内容
ansicode
TypeScript (Deno / Bun / Node)

在 TypeScript(Deno、Bun、Node)中使用 ANSI 转义码

TypeScript 本身会被转译 —— 实际写入终端的字节与 JavaScript 一致。三种 TS 运行时的差异在于**标准库的写入调用**:Node 用 `process.stdout.write`,Deno 用 `Deno.stdout.writeSync`(或 `console.log`),Bun 同时支持 Node 的 `process.stdout` shim 与自身的 `Bun.write(Bun.stdout, …)`。三者都按字节透传。带类型的便利 API 可选 `picocolors`(零依赖,通过 `npm:` / `jsr:` / 直接 import 在每个运行时中可用)、Deno 自带的 `@std/fmt/colors`,或更小巧、同构的 `kolorist`。`chalk` 5+ 仅支持 ESM,可在 Node / Bun / Deno(`npm:chalk`)下使用。

推荐库

  • picocolors

    零依赖、约 100 行、完整类型。冷启动最快,也是三个运行时唯一可以用同一种方式导入的库(Deno 用 `npm:picocolors`,Node / Bun 直接 `import`)。

  • chalk

    经典的可链式 API(`chalk.bold.red('oops')`),具备完整 TypeScript 类型,自动检测 16 / 256 / 16M 色支持。v5+ 为纯 ESM —— 兼容 Node 14.16+、Bun,以及通过 `npm:chalk` 的 Deno。

  • @std/fmt/colors (Deno)

    Deno 自带的彩色辅助函数 —— `red()`、`bold()`、`bgBlue()` —— 无需安装、无依赖。纯 Deno 脚本中使用;跨运行时代码请用 picocolors / kolorist,使同一份文件能在各运行时执行。

  • kolorist

    极小的同构彩色辅助库 —— 可在 Node / Bun / Deno **以及**浏览器中工作(在 DevTools 中自动回退到 CSS `%c` 样式)。Vite、marko、preact 都在使用。端到端类型完整。

常用写法

运行时感知的直接写入(Node / Deno / Bun)
// Picks the stdout API of whichever runtime is executing. All three are
// byte-clean — \x1b sequences pass through unchanged.
const RED_BOLD = '\x1b[1;31m';
const RESET = '\x1b[0m';
const line = `${RED_BOLD}error:${RESET} permission denied\n`;

declare const Deno: { stdout: { writeSync(b: Uint8Array): number } } | undefined;
declare const Bun: { stdout: unknown; write(d: unknown, s: string): Promise<number> } | undefined;

if (typeof Deno !== 'undefined') {
  Deno.stdout.writeSync(new TextEncoder().encode(line));
} else if (typeof Bun !== 'undefined') {
  await Bun.write(Bun.stdout, line);
} else {
  process.stdout.write(line);
}
使用模板字面量类型的带类型 SGR 辅助函数
// Compile-time check that you only pass known SGR codes — typos fail tsc.
type SGR =
  | 0 | 1 | 2 | 3 | 4 | 7 | 22 | 23 | 24 | 27
  | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39
  | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97;

const sgr = (text: string, ...codes: SGR[]): string =>
  `\x1b[${codes.join(';')}m${text}\x1b[0m`;

console.log(sgr('error:', 1, 31), 'permission denied');
console.log(sgr('ok', 32));
Deno:使用 @std/fmt/colors(无需安装)
// deno run --allow-env script.ts
import { bold, red, rgb24 } from 'jsr:@std/fmt/colors';

console.log(`${bold(red('error:'))} permission denied`);
console.log(rgb24('lavender truecolor', 0xcba6f7));
跨运行时统一的 NO_COLOR 检测
// Works under Node, Bun, and Deno — each exposes env vars differently.
declare const Deno: { env: { get(k: string): string | undefined }; stdout: { isTerminal(): boolean } } | undefined;

const env = (k: string): string | undefined =>
  typeof Deno !== 'undefined' ? Deno.env.get(k) : process.env[k];

const isTTY = (): boolean =>
  typeof Deno !== 'undefined' ? Deno.stdout.isTerminal() : Boolean(process.stdout.isTTY);

const USE_COLOR = isTTY() && env('NO_COLOR') === undefined && env('FORCE_COLOR') !== '0';

export const paint = (text: string, sgr: string): string =>
  USE_COLOR ? `\x1b[${sgr}m${text}\x1b[0m` : text;

相关序列

其他语言