面试题答案
一键面试可能出现类型错误的原因
- 属性冲突:虽然
Base
和Editable
定义看似无冲突,但在实际使用场景中,可能存在隐藏的类型不兼容问题。例如,在对对象进行类型断言时,可能将不符合预期类型的值赋予了id
或createdAt
属性,导致类型错误。 - 类型断言不准确:使用类型断言时,可能没有准确判断对象的实际类型。例如,对象实际类型可能只部分符合
EditableBase
,但类型断言强制将其视为完全符合,导致访问不存在或类型不匹配的属性时出错。
解决方案及优缺点
- 使用类型守卫
- 实现方式:在使用对象属性之前,通过类型守卫函数判断对象是否具有特定属性及属性类型是否正确。例如:
function isEditableBase(obj: any): obj is EditableBase {
return 'id' in obj && typeof obj.id ==='string' && 'createdAt' in obj && obj.createdAt instanceof Date && 'update' in obj && typeof obj.update === 'function';
}
let myObj: any;
if (isEditableBase(myObj)) {
myObj.update();
console.log(myObj.id);
console.log(myObj.createdAt);
}
- **优点**:增加代码的健壮性,确保在使用属性前对象类型符合预期,减少运行时错误。
- **缺点**:增加代码量,每次使用对象属性前都需要进行类型守卫判断,影响代码简洁性。
2. 使用interface
合并
- 实现方式:在定义EditableBase
时,直接将Base
和Editable
的属性合并在一个新的interface
中,确保类型定义清晰。
interface Base {
id: string;
createdAt: Date;
}
interface Editable {
update(): void;
}
interface EditableBase extends Base, Editable {}
let myObj: EditableBase = {
id: '123',
createdAt: new Date(),
update: () => {}
};
- **优点**:类型定义清晰,减少因交叉类型可能产生的潜在问题,代码可读性较好。
- **缺点**:若`Base`和`Editable`接口有大量属性,合并后`EditableBase`接口可能变得冗长。
3. 使用type
别名
- 实现方式:与交叉类型类似,但使用type
别名可以更灵活地处理复杂类型。
interface Base {
id: string;
createdAt: Date;
}
interface Editable {
update(): void;
}
type EditableBase = Base & Editable;
let myObj: EditableBase = {
id: '123',
createdAt: new Date(),
update: () => {}
};
- **优点**:保持了交叉类型的灵活性,同时与`interface`合并相比,语法更简洁,适用于简单类型组合。
- **缺点**:对于复杂类型关系,不如`interface`合并清晰,且在处理类型扩展等方面相对较弱。