为复杂嵌套对象与数组状态写严格接口,核心是分层建模、显式约束、避免any,借助递归类型和交叉类型应对深度结构;关键在于可推导、可复用、可维护,而非堆砌点号路径。
为复杂的嵌套对象与数组状态写严格接口,核心是分层建模、显式约束、避免 any,并借助递归类型和交叉类型应对深度结构。关键不在“写全”,而在“可推导、可复用、可维护”。
不要在一个大接口里堆满点号路径;而是按业务语义分层定义小接口,再组合引用。例如用户带地址、订单带商品列表的场景:
User、Address、Product
OrderItem 包含 product: Product 和 quantity: number
AppState 中 currentUser: User | null,orders: OrderItem[]
这样既利于 IDE 补全,也方便单元测试时单独 mock 某一层。
当结构深度不确定(比如文件目录、多级评论),用自引用接口保证类型穿透到底层:
type TreeNode = { id: string; name: string; children?: TreeNode[] }
interface Comment { id: string; content: string; replies?: Comment[] }
TypeScript 编译器会在 50 层内完整展开推导,访问 comment.replies[0]?.replies[1]?.id 时能准确提示类型,不会报 any 或 undefined 错误。
避免只写 items: any[] 或 items: object[] —— 这等于放弃类型保护:
items: Product[] 明确每个元素是 Product 实例fields: (TextInputField | NumberInputField | DateField)[]
as const 固定字面量数组类型,例如权限列表:permissions: readonly ['read', 'write', 'delete']
接口定义完,必须在运行时上下文中生效才真正起作用:
state: (): UserState => ({ ... }),确保 this.users[0].email 有完整类型提示<script setup lang="ts"> 中,defineProps<{ config: AppConfig }>(),而非 Object as PropType<AppConfig>(后者仅用于遗留兼容)theme?: 'light' | 'dark'、readonly createdAt: Date,让调用方清楚哪些能改、哪些不能改