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

如何为ExcelScript Stub编写ExcelJS的TypeScript包装器?

如何将ExcelScript桩代码包装为ExcelJS适配层

核心思路是保留ExcelScript对外暴露的类、方法和类型定义,在内部用ExcelJS的实例实现具体逻辑,同时处理两者的API差异:同名方法做参数/返回值适配,ExcelJS缺失的方法自行补全逻辑。

步骤1:安装ExcelJS

先安装依赖包:

npm install exceljs @types/exceljs --save

步骤2:改造ExcelScript命名空间的类

每个类内部持有对应的ExcelJS实例,将ExcelScript的方法调用转发到ExcelJS,同时处理差异:

import * as exceljs from 'exceljs';

export namespace ExcelScript {
  export class Workbook {
    // 持有ExcelJS的Workbook实例
    private readonly _workbook: exceljs.Workbook;

    constructor() {
      this._workbook = new exceljs.Workbook();
    }

    getWorksheet(indexOrName: string | number): Worksheet {
      const jsWorksheet = this._workbook.getWorksheet(indexOrName);
      if (!jsWorksheet) {
        // 模拟桩代码行为,返回新工作表实例
        const newJsSheet = this._workbook.addWorksheet();
        return new Worksheet(newJsSheet);
      }
      return new Worksheet(jsWorksheet);
    }

    // 补充ExcelScript可能需要的保存方法
    save(filePath: string): Promise<void> {
      return this._workbook.xlsx.writeFile(filePath);
    }
  }

  export enum RangeCopyType {
    values
  }

  export class Worksheet {
    private readonly _worksheet: exceljs.Worksheet;

    constructor(worksheet: exceljs.Worksheet) {
      this._worksheet = worksheet;
    }

    getCell(x: number, y: number): Range {
      // ExcelJS行列也是1-based,直接调用对应方法
      const jsCell = this._worksheet.getCell(x, y);
      return new Range(jsCell);
    }

    getRange(x: number | string, y?: string): Range {
      let jsRange: exceljs.Range;
      if (typeof x === 'number' && y) {
        jsRange = this._worksheet.getRange(x, y);
      } else {
        jsRange = this._worksheet.getRange(x as string);
      }
      return new Range(jsRange);
    }

    getTables(): Table[] {
      return this._worksheet.tables.map(table => new Table(table));
    }
  }

  export class Range {
    private readonly _range: exceljs.Range;

    constructor(range: exceljs.Range) {
      this._range = range;
    }

    setValue(value: string | number | boolean | Date): Range {
      this._range.value = value;
      return this; // 保持ExcelScript的链式调用特性
    }

    copyFrom(sourceRange: Range, copyType: RangeCopyType): [][] {
      const options: exceljs.CopyOptions = {};
      if (copyType === RangeCopyType.values) {
        options.valuesOnly = true;
      }
      this._range.copyFrom(sourceRange._range, options);
      return this._range.values as [][];
    }

    getText(): string {
      return this._range.text as string;
    }

    getTexts(): [][] {
      return this._range.text as [][];
    }

    getValue(): string | number | boolean | Date {
      return this._range.value as string | number | boolean | Date;
    }

    setNumberFormat(formatString: string): void {
      this._range.numFmt = formatString;
    }

    convertDataTypeToText(): void {
      // ExcelJS无此方法,自行实现:遍历单元格转文本格式
      this._range.eachCell({ includeEmpty: true }, cell => {
        if (cell.value != null) {
          cell.value = String(cell.value);
          cell.numFmt = '@'; // 设置为文本格式
        }
      });
    }
  }

  export class Table {
    private readonly _table: exceljs.Table;

    constructor(table: exceljs.Table) {
      this._table = table;
    }

    getRange(x?: string, y?: string): Range {
      return new Range(this._table.range);
    }

    getTexts(): [][] {
      return this._table.range.text as [][];
    }
  }
}

关键适配点说明

  • 实例持有:每个ExcelScript类内部都包含对应的ExcelJS实例,所有操作最终委托给这个实例执行。
  • 同名方法适配:比如getWorksheet、getCell等,直接映射到ExcelJS的同名方法,对齐参数和返回值类型。
  • 缺失方法补全:像convertDataTypeToText这类ExcelJS没有的方法,通过遍历单元格、修改值和格式的方式自行实现。
  • 链式调用保持:ExcelScript的方法(如setValue)支持链式调用,包装时注意返回当前实例。

使用示例

import { ExcelScript } from './your-wrapper-file';

async function test() {
  const workbook = new ExcelScript.Workbook();
  const worksheet = workbook.getWorksheet('Sheet1');
  
  // 设置单元格值并指定格式
  worksheet.getCell(1, 1).setValue('Hello').setNumberFormat('@');
  
  // 复制单元格值
  const sourceRange = worksheet.getCell(1,1);
  worksheet.getCell(1,2).copyFrom(sourceRange, ExcelScript.RangeCopyType.values);
  
  // 保存文件
  await workbook.save('./test.xlsx');
}

test();

内容的提问来源于stack exchange,提问作者Arkanit

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:57:27