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' 字面量不在允许列表(多半拼错)
相关推荐
Bode_20021 小时前
构建制造业知识库
前端·智能制造系统·业务流程再造
JAVA老架构AI智能化1 小时前
多图叠加比对
前端·javascript·chrome
ShineWinsu1 小时前
对于HTML:HTML常见标签的解析—上
前端·面试·html·浏览器·标签·图片·超链接
百度一下吧2 小时前
HTML5 新增标签与 Web Components 使用指南
前端·html·html5
志尊宝2 小时前
Vue3 零基础每日笔记(081):富文本编辑器集成 wangEditor 5——封装
前端·javascript·vue.js·笔记·信息可视化·echarts
deli0072 小时前
纯向量检索漏掉的召回,BM25 加向量混合能补回来吗?5 组实测
前端
志尊宝2 小时前
Vue3 零基础每日笔记(080):Vue3 + ECharts 数据可视化——封装可复用图表组件
前端·javascript·vue.js·笔记·信息可视化·echarts
阿狗童鞋2 小时前
前端工程化实战指南
前端
CappuccinoRose2 小时前
CSS 动效基础
前端·css·动画·animation·transition