跳到主要内容
全部文章

写好 TypeScript 的 6 个实用习惯

不聊类型体操,只聊日常开发里真正能减少 bug、提升可读性的 TypeScript 习惯。

发布于 2 分钟阅读
目录

TypeScript 上手容易,写「好」却需要刻意练习。这里的「好」不是炫技,而是:让编译器替你多想一步,让半年后的自己读得懂。以下 6 个习惯,都是我在真实项目里反复验证过的。

1. 让 unknown 成为 any 的替代品

any 会把类型检查在传播路径上全部关掉。实在拿不准类型时,用 unknown 强迫自己先收窄:

function parse(raw: string): unknown {
  return JSON.parse(raw);
}

const data = parse(input);
if (typeof data === 'object' && data !== null && 'id' in data) {
  // 这里 TS 已经知道 data 是 object
}

2. 用判别联合建模「状态」

有状态机味道的需求,优先用判别联合而不是一堆布尔位:

type FetchState<T> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; message: string };

好处是非法状态无法表达——你不可能写出「成功但没有数据」的对象。

3. satisfies 比 as 诚实

as 是「信我」,satisfies 是「帮我验证」:

const routes = {
  home: '/',
  blog: '/blog/',
  about: '/about/',
} satisfies Record<string, `/${string}/`>;

写错路径格式会立刻报错,而且 routes 保留了字面量类型的推导。

4. 从源头收窄,而不是到处断言

拿到外部数据(接口响应、URL 参数、localStorage)时,在边界处做一次完整校验,内部就放心用:

const stored = localStorage.getItem('theme');
const theme = stored === 'dark' ? 'dark' : 'light';

一行收窄,后面全是干净类型。

5. 善用模板字面量类型

URL、事件名、CSS 变量这类字符串,可以用模板字面量类型描述结构:

type CategoryPath = `/categories/${string}/`;

function goto(path: CategoryPath) {
  window.location.assign(path);
}

goto('/blog/'); // ❌ 类型错误

6. 检查开关全部打开

最后也是最重要的:配好 tsconfig,让工具替你把关。

配置 作用
strict: true 一揽子严格检查,必开
noUncheckedIndexedAccess 索引访问结果视为 T | undefined
noEmit 只做类型检查,交给打包器产物
{
  "extends": "astro/tsconfigs/strict",
  "compilerOptions": {
    "noUncheckedIndexedAccess": true
  }
}

小结

类型系统的价值不在于注解数量,而在于把运行时才暴露的问题搬到编译期。上面 6 个习惯没有一个是新知识,但每一里都少踩一个坑。