You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 11:05:26