在 TypeScript 中,类型系统是基于结构类型(structural typing)而不是名义类型(nominal typing)。这意味着 TypeScript 关注的是类型的形状(结构),而不是它们的名字或声明方式。只要两个类型的结构兼容,它们就可以互相赋值。
结构类型系统的理解
结构匹配:如果一个对象具有另一个对象所需的所有属性和方法,那么这两个对象的类型就是兼容的。
鸭子类型:如果它走起来像鸭子,叫起来像鸭子,那么它就是鸭子。即使两个类型没有显式的关系,只要它们的结构相同,它们就可以互相赋值。
示例代码
接口定义
interface Point {
x: number;
y: number;
}
interface Coordinate {
x: number;
y: number;
}
结构兼容性
let point: Point = { x: 10, y: 20 };
let coordinate: Coordinate = { x: 30, y: 40 };
// 由于 Point 和 Coordinate 的结构相同,它们是兼容的
point = coordinate;
coordinate = point;
类的结构兼容性
class PointClass {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
let pointInstance: PointClass = new PointClass(50, 60);
// PointClass 的实例与 Point 结构兼容
point = pointInstance;
函数参数的结构兼容性
interface LikeFile {
name: string;
size: number;
type: string;
}
function processFile(file: LikeFile) {
console.log(`Processing file: ${file.name}`);
}
const file = { name: "example.txt", size: 1024, type: "text/plain", lastModified: Date.now() };
// 即使 file 对象有额外的属性 lastModified,它仍然与 LikeFile 结构兼容
processFile(file);
在项目中的应用
FileUploadProps
接口定义了一个 files
属性,它可以是 Blob
、File
或 LikeFile
类型的单个对象或数组。这些类型之间的兼容性可以通过结构类型系统来理解:
export interface FileUploadProps {
files: Blob | Blob[] | File | File[] | LikeFile | LikeFile[];
// 其他属性省略
}
由于 TypeScript 的结构类型系统,只要 Blob
、File
和 LikeFile
的结构兼容,它们就可以互相赋值。例如,如果 LikeFile
的结构包含 Blob
和 File
的所有属性,那么它们就是兼容的。
总结
TypeScript 的结构类型系统使得类型检查更加灵活,只要类型的结构(属性和方法)兼容,它们就可以互相赋值。这种机制在处理复杂类型和接口时非常有用,减少了不必要的类型转换和显式声明。