Google Sheets导出批注脚本报错:TypeError无法读取undefined的setName
Google Apps Script导出批注时报错:TypeError: Cannot read properties of undefined (reading 'setName')
问题背景
我使用以下脚本从Google Sheets导出批注,在同一电子表格内生成REPORT工作表:
function myFunction() { const excludeSheetNames = ['START', 'MASTER', 'REPORT']; // Exclude sheet names. const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheets = ss.getSheets(); const sheett = sheets.find(s => !excludeSheetNames.includes(s.getSheetName())); const [head, , , ...rows] = sheett.getRange("A1:A" + sheett.getLastRow()).getValues(); const res = DocsServiceApp.openBySpreadsheetId(ss.getId()).getComments(); res.forEach(({ sheetName, comments }, h) => { sheetName = sheets[h].getSheetName(); if (!excludeSheetNames.includes(sheetName)) { head.push(sheetName); rows.forEach((e, i) => { const t = comments.find(f => i == f.range.row - 4); e.push(t ? t.comment[0].comment.trim() : null); }); } }); const values = [head, ...rows]; const dstSheet = ss.getSheetByName("REPORT") || ss.insertSheet("REPORT"); dstSheet.clearContents().getRange(1, 1, values.length, values[0].length).setValues(values); }
运行脚本时触发如下错误:
9:50:13 AM Error TypeError: Cannot read properties of undefined (reading 'setName') (anonymous) @ ExcelApp.gs:408 getImagesAsObject @ ExcelApp.gs:379 (anonymous) @ ExcelApp.gs:39 getAll @ ExcelApp.gs:34 getComments @ SpreadsheetAppp.gs:49 myFunction @ REPORT.gs:8
我已共享包含该脚本的Google Sheet文件,可直接查看脚本及表格结构。
问题分析
从报错堆栈可以明确:错误并非来自你编写的REPORT.gs代码,而是来自引入的第三方库(ExcelApp.gs和SpreadsheetAppp.gs)。当调用DocsServiceApp.openBySpreadsheetId(ss.getId()).getComments()时,库内部的getImagesAsObject方法尝试读取一个未定义对象的setName属性,导致抛出类型错误。
解决方案
方案1:替换第三方库,使用原生API实现需求
直接使用Google Apps Script官方提供的SpreadsheetApp API读取批注,完全规避第三方库的兼容性问题。修改后的脚本如下:
function exportCommentsToReport() { // 排除不需要处理的工作表名称 const excludeSheetNames = ['START', 'MASTER', 'REPORT']; const ss = SpreadsheetApp.getActiveSpreadsheet(); // 过滤出需要处理的工作表 const targetSheets = ss.getSheets().filter(sheet => !excludeSheetNames.includes(sheet.getSheetName())); if (targetSheets.length === 0) return; // 无有效工作表时直接退出 // 获取第一个有效工作表的A列数据,保留原脚本的表头和行结构(跳过前3行) const firstSheet = targetSheets[0]; const allAValues = firstSheet.getRange(1, 1, firstSheet.getLastRow()).getValues(); const [head, , , ...rows] = allAValues; // 遍历每个目标工作表,收集对应行的批注 targetSheets.forEach(sheet => { const sheetName = sheet.getSheetName(); head.push(sheetName); // 获取当前工作表的所有批注 const sheetComments = sheet.getComments(); // 为每一行匹配对应批注 rows.forEach((rowData, rowIndex) => { // 原脚本中对应行号为索引+4,保持逻辑一致 const targetRowNumber = rowIndex + 4; const matchedComment = sheetComments.find(comment => comment.getRow() === targetRowNumber); // 填充批注内容(无批注则填null) rowData.push(matchedComment ? matchedComment.getValue().trim() : null); }); }); // 创建或更新REPORT工作表 const reportSheet = ss.getSheetByName("REPORT") || ss.insertSheet("REPORT"); reportSheet.clearContents(); // 写入数据到REPORT表 reportSheet.getRange(1, 1, rows.length + 1, head.length).setValues([head, ...rows]); }
方案2:修复第三方库的错误(若必须使用原库)
如果一定要依赖DocsServiceApp,可以尝试以下操作:
- 打开脚本编辑器,点击「扩展」>「Apps Script」,然后依次点击「库」,查看
ExcelApp和SpreadsheetAppp的库版本,切换到最新稳定版本 - 若库代码是手动复制到项目中的,打开
ExcelApp.gs文件,定位到第408行,检查调用setName的对象是否已正确初始化,添加空值判断避免读取未定义属性
脚本说明
修改后的原生API版本脚本保持了原脚本的核心逻辑:
- 排除指定的工作表
- 以第一个有效工作表的A列为基础结构(跳过前3行)
- 为每个目标工作表添加列,填充对应行的批注内容
- 自动创建或更新REPORT工作表,写入最终数据
内容的提问来源于stack exchange,提问作者dek
相关产品推荐
相关产品推荐

