如何在类型收窄后安全访问数组元素的属性?
问题解决:TypeScript动物数组类型收窄与属性校验
问题根源
你原代码的核心问题在于泛型Animal接口没有把type和actions的类型做强绑定:
- 当你使用
Animal<AnimalTypes>时,type是'dog'|'cat'的联合类型,actions是DogActions|CatActions的联合类型,两者是独立的,TypeScript无法通过type的判断来推断actions的具体类型,导致访问woof或purr时报错。 - 这种定义方式也无法阻止错误属性的赋值,因为泛型的宽松匹配允许联合类型的任意组合。
解决方案:使用联合类型替代泛型接口
把Animal定义为具体动物类型的联合类型,让每个动物的type是字面量类型,与对应的actions严格绑定,TypeScript就能自动通过type做类型收窄,同时阻止错误属性的赋值。
修改后的代码:
interface DogActions { woof: true } interface CatActions { purr: true } // 定义具体的狗类型,type为字面量'dog',actions严格对应DogActions type Dog = { type: 'dog' actions: DogActions } // 定义具体的猫类型,type为字面量'cat',actions严格对应CatActions type Cat = { type: 'cat' actions: CatActions } // Animal是狗或猫的联合类型 type Animal = Dog | Cat // 数组类型为Animal[],非法赋值会直接触发TypeScript错误 const arr: Animal[] = [ { type: 'dog', actions: { woof: true }}, // 合法 { type: 'cat', actions: { purr: true }}, // 合法 // { type: 'dog', actions: { purr: true }} // 取消注释会报错:属性'purr'不在DogActions中 ] arr.forEach(animal => { if (animal.type === 'dog') { console.log(animal.actions.woof) // 无报错,TypeScript已推断为Dog类型 } else if (animal.type === 'cat') { console.log(animal.actions.purr) // 无报错,TypeScript已推断为Cat类型 } })
服务器数据的类型校验
因为你从服务器获取数据,无法直接控制数据格式,建议添加运行时类型守卫来确保数据合法性:
// 类型守卫函数,校验对象是否为合法的Animal function isAnimal(obj: unknown): obj is Animal { if (typeof obj !== 'object' || obj === null) return false const animal = obj as Animal switch (animal.type) { case 'dog': return typeof animal.actions === 'object' && animal.actions !== null && 'woof' in animal.actions && animal.actions.woof === true case 'cat': return typeof animal.actions === 'object' && animal.actions !== null && 'purr' in animal.actions && animal.actions.purr === true default: return false } } // 模拟从服务器获取数据 async function fetchAnimals() { const res = await fetch('/api/animals') const data = await res.json() return data } // 使用时先校验 fetchAnimals().then(serverData => { if (Array.isArray(serverData) && serverData.every(isAnimal)) { const arr: Animal[] = serverData arr.forEach(animal => { if (animal.type === 'dog') { console.log(animal.actions.woof) } else { console.log(animal.actions.purr) } }) } else { console.error('服务器返回的数据格式不符合要求') } })
内容的提问来源于stack exchange,提问作者akivajgordon
相关产品推荐
相关产品推荐

