如何在TypeScript中扩展File类型?解决Attachment类构造赋值问题
如何正确继承JavaScript的File类型并添加自定义属性?
问题原因
File 实例的核心属性(如 name、size、type)都是只读的自有属性,Object.assign 尝试向新实例赋值这些属性时会直接失败——只读属性无法被重新赋值,所以最终只有自定义属性被保留。
解决方法
有两种可靠的实现方式,可根据你的业务需求选择:
1. 原型继承(让实例同时属于 File 和 Attachment 类型)
这种方式通过修改原型链,让 Attachment 实例继承 File 的所有属性和方法,同时保留自定义属性。适合需要实例直接兼容 File 类型的场景(比如传入要求 File 参数的 API)。
// 定义 Attachment 构造函数 function Attachment(file, url) { // 用原 File 的参数创建新的 File 实例 const fileInstance = new File( [file], file.name, { type: file.type, lastModified: file.lastModified } ); // 将原型指向 Attachment 的原型,实现继承关系 Object.setPrototypeOf(fileInstance, Attachment.prototype); // 添加自定义属性 fileInstance.url = url; fileInstance.isVideo = file.type.startsWith('video/'); return fileInstance; } // 建立原型链关联,确保继承正确 Attachment.prototype = Object.create(File.prototype); Attachment.prototype.constructor = Attachment; // 使用示例 const originalFile = new File(['test'], 'video.mp4', { type: 'video/mp4' }); const attachment = new Attachment(originalFile, 'https://example.com/video.mp4'); console.log(attachment instanceof File); // true console.log(attachment instanceof Attachment); // true console.log(attachment.name); // 'video.mp4' console.log(attachment.isVideo); // true
2. 包装模式(组合优于继承,扩展性更强)
这种方式不直接继承 File,而是将 File 实例作为内部属性,通过 getter 代理所有 File 的属性和方法。适合不需要严格继承 File 类型、更注重扩展性的场景。
class Attachment { constructor(file, url) { this._file = file; this.url = url; this.isVideo = file.type.startsWith('video/'); } // 代理 File 的核心只读属性 get name() { return this._file.name; } get size() { return this._file.size; } get type() { return this._file.type; } get lastModified() { return this._file.lastModified; } get lastModifiedDate() { return this._file.lastModifiedDate; } get webkitRelativePath() { return this._file.webkitRelativePath; } // 代理 File 的方法 slice(start, end, contentType) { return this._file.slice(start, end, contentType); } // 自定义方法示例:序列化实例 toJSON() { return { name: this.name, size: this.size, type: this.type, url: this.url, isVideo: this.isVideo }; } } // 使用示例 const originalFile = new File(['test'], 'video.mp4', { type: 'video/mp4' }); const attachment = new Attachment(originalFile, 'https://example.com/video.mp4'); console.log(attachment.name); // 'video.mp4' console.log(attachment.isVideo); // true console.log(attachment.slice(0, 5)); // 返回 Blob 实例
优劣势对比
- 原型继承:实例完全兼容 File 类型,但受限于 File 构造函数的参数约束,灵活性稍弱。
- 包装模式:无需处理内置对象继承的潜在坑,扩展性更强,但实例不属于 File 类型,若需要传入要求 File 的 API,可直接传递
attachment._file。
内容的提问来源于stack exchange,提问作者GoncaloNGT
相关产品推荐
相关产品推荐

