TypeScript 02:interface、type 与类型收窄

TypeScript 02:interface、type 与类型收窄

1. interface:给对象形状起名字

第 1 课的 { name: string; age: number } 每次都要重抄一遍------起个名字就能复用:

ts 复制代码
interface User {
  name: string
  age: number
}

function greet(u: User) {
  return `你好,${u.name}`
}

greet({ name: 'Tom', age: 18 }) // ✅
greet({ name: 'Tom' }) // ❌ Property 'age' is missing in type 'User'

形状可以继承:

ts 复制代码
interface Vip extends User {
  level: number
}

const v: Vip = { name: 'Tom', age: 18, level: 3 }

2. type:另一种起名方式

type 也能给形状起名,还擅长做 interface 做不到的事------给联合、字面量起名:

ts 复制代码
type ID = string | number
type Status = 'loading' | 'success' | 'error'

let page: Status = 'loading'
page = 'loaded' // ❌ Type '"loaded"' is not assignable to type 'Status'(拼错立刻暴露)

怎么选 :对象形状两者都能用,团队统一一种即可;联合类型、字面量类型只能用 type。

3. 可选属性 ?: 与只读 readonly

ts 复制代码
interface Profile {
  name: string
  email?: string // 可有可无,实际类型是 string | undefined
  readonly id: number // 只能读,不能改
}

const p: Profile = { name: 'Tom', id: 1 } // 不写 email 合法
p.id = 2 // ❌ Cannot assign to 'id' because it is a read-only property

可选属性的实际类型是 string | undefined,用之前要确认存在:

ts 复制代码
if (p.email) {
  sendTo(p.email) // 这里 TS 知道 email 一定是 string
}

4. 字面量类型与 as const

string 是「任意字符串」,'loading' 本身也是一个类型------值被锁死为这一个:

ts 复制代码
const ROUTES = {
  home: '/',
  about: '/about',
} as const // 每个字段锁成字面量类型 '/' 和 '/about',且全部只读

ROUTES.home = '/x' // ❌ Cannot assign to 'home' because it is a read-only property

5. 类型收窄:使用联合类型的前提

联合类型的值,不能直接用某一方的特有能力------必须先收窄:

ts 复制代码
function describe(id: string | number) {
  // ❌ id.toUpperCase():Property 'toUpperCase' does not exist on type 'string | number'

  if (typeof id === 'string') {
    return id.toUpperCase() // ✅ 这里 TS 知道是 string
  }
  return id.toFixed(2) // ✅ 这里 TS 知道是 number
}

三种常用收窄手段:

ts 复制代码
if (typeof x === 'string') {} // ① typeof:区分原始类型
if ('fly' in animal) {} // ② in:对象有没有这个字段
if (r.ok === true) {} // ③ 具体值比较(配合字面量类型)

③ 的经典形态是可辨识联合------后端接口最常见:

ts 复制代码
type ApiResult = { ok: true; data: string[] } | { ok: false; message: string }

function handle(r: ApiResult) {
  if (r.ok) {
    return r.data.length // 收窄到成功分支,才有 data
  }
  return r.message // 收窄到失败分支,才有 message
}

6. unknown:安全的 any

any 是「随便用」;unknown 是「类型未知,但用之前必须收窄」:

ts 复制代码
const input: unknown = JSON.parse(text)

input.toFixed(2) // ❌ 'input' is of type 'unknown'

if (typeof input === 'number') {
  input.toFixed(2) // ✅ 收窄后才能用
}

外部数据(接口返回、JSON)优先按 unknown 处理,逼自己先判断再用。

7. 高频报错速查

报错 人话
`Property 'x' does not exist on type 'string number'`
'input' is of type 'unknown' unknown 必须先收窄再使用
Cannot assign to 'id' because it is a read-only property 给 readonly 赋值了
Type '"loaded"' is not assignable to type 'Status' 字面量不在允许列表(多半拼错)
相关推荐
腾科IT教育20 小时前
TypeScript 泛型(Generics):类型占位符实现复用与安全
安全·typescript·泛型
jktantan1 天前
Vue keep-alive 切标签后滚动位置回顶?因为 onDeactivated 里读到的 scrollTop 是 0
前端·javascript·vue.js
2601_962885721 天前
quotes 字段全解:涨跌幅、振幅、换手率的口径与单位
java·前端·spring
excel1 天前
encodeURI 和 encodeURIComponent 有什么区别?
前端
前端精髓1 天前
调用openrouter的免费API模型
java·前端·javascript
赛博守夜人1 天前
AI安全攻防与治理之十四:AI 安全测试不能脱离传统安全,Web、API、移动端与模型攻击面的组合拳
前端·人工智能·安全
开开心心_Every1 天前
快速隐藏程序工具自定义快捷键一键切换
java·开发语言·前端·spring·智能手机·word·intellij-idea
networknomad1 天前
OpenReplay:自己搭的会话回放工具,给前端排错用的
前端·其他
缓慢更新1 天前
AI 辅助生成单测:从接口定义到用例的流水线
java·服务器·前端·网络·数据库·人工智能
陈随易1 天前
AI 运维服务器,安全又可靠的方法
前端·后端·程序员