将 Typescript 与 Google Apps 脚本结合使用

Use Typescript with Google Apps Script

我想为我的 Google Apps 脚本 (GAS) 项目使用 Typescript,但我找不到将我的代码编译成 GAS 接受的东西的方法。

GAS 不支持导出,Typescript 似乎不喜欢通过全局范围访问变量(它需要 imports/require,因此需要导出)。

我正在寻找以下任何我认为对我有用的解决方案:

1) Babel 插件等可以删除所有 Import 和 Export 语句及其属性名称(要求我不使用相同的方法名称,我不这样做。

所以:

import MyLibrary from './library';
export function greetJohn() { MyLibrary.greet('John'); }
export default { greetJohn }

变为:

function greetJohn() { greet('John'); }

2) 更改打字稿,使其可以查看全局范围

3) Babel 插件等将所有 .ts 文件组合成一个 .js 文件并通过将每个文件视为 Object/function.

来转换 import/export 语句

过去几周我一直在研究类似的情况(不使用 TypeScript 但仍然 ES6/ES7)。

我发现的一些内容可能对您想要实现的目标有所帮助:

  • GAS webpack plugin 允许您使用 webpack 在 GAS 中加载模块,方法是检测您何时分配给全局对象,然后生成 GAS 可以 运行 的顶级函数。这意味着您的导入和导出都将由 webpack 处理,因此您不必删除它们。
  • 我无法使 import * as x from y 语法正常工作,但是 import { x } from yimport x from y 在使用 webpack 时工作正常。
  • 您可以使用 HTML loader.
  • 将 HTML 作为字符串包含在您的包中

如果您不想使用 webpack,一种解决方案是将所有代码放在一个 app.ts 文件中,创建一个包含所有函数的对象,将函数设置为顶级所以它们可以被 GAS 拾取。您还可以导出容器对象并在测试套件中使用它。当你用 Babel 编译时,使用 babel-plugin-transform-remove-export 插件删除导出语句。

const app = {
  onInstall: () => { ...
  },
  onOpen: () => { ...
  }
}

const { onOpen, onInstall } = app;

export { app };

现在可以使用 Typescript 开发 Google Apps 脚本项目,但这不能直接在 Apps 脚本编辑器上完成。

根据Develop Apps Script using TypeScript the easier way is by using clasp

相关

使用 TypeScript with Google App Script is to use clasp 的最佳(和推荐)方式。

  1. 安装表扣:npm install @google/clasp -g
  2. 登录:clasp login
  3. 创建项目:clasp create [scriptTitle]
  4. 可选:将 appsscripts.json 文件中的时区更改为 this list 中最合适的时区。
  5. 安装类型:npm i -S @types/google-apps-script
  6. 创建 tsconfig.json 文件:
    { "compilerOptions": { "lib": [ "esnext" ], "experimentalDecorators": true } }
  7. 在 .ts 文件中编写代码
  8. 使用 clasp push
  9. 推送您的代码
  10. 刷新您的脚本页面和运行您的函数。

注意:您不需要使用 importexport。可以跨文件访问变量。

背景

自从您写下这个问题后,情况发生了变化,现在对 TypeScript 的 AppsScript 开发有了更好的支持。 正如 Aliabbas Merchant 所说,将 TS 编译为 GAS 的最佳方法是在后台使用 clasp, which is a CLI tool for developing AppsScript apps. Clasp uses ts2gas 库将 TS 转换为 GAS,因此不再需要 Webpack 或任何其他仅用于将代码转换为 AppsScript 的捆绑器。

Aliabbas Merchant 没有提到的是 ts2gas 不(还!)支持 export 语法,这会在开发时导致 linter 错误,并且不会被很好地接受IDE(即使禁用 linter,IDE 也不会识别导入的变量,也不会将它们视为对导出的引用...)

问题

问题源于以下事实:AppsScript 不使用模块系统,并且每个定义的顶级 var 也可以从其他文件访问(与将文件“包装”为模块的 TS 相反)。 当前版本的 ts2gas 的问题在于它转译了以下语句:

export var x = 5;

进入:

exports.x = 5

因此,在 clasp 将 .ts 转换为 .gs 之后,当 .gs 的另一个文件试图访问导出的 var 时,它找不到它。实际上,这个变量并没有像预期的那样存储为全局变量,而是在 exports 对象(它本身就是一个全局变量)中。如果我们能以某种方式“欺骗”编译器,那么它既能将 var 保存在全局环境中,即使它也被导出(这样我们就可以毫无错误地使用 TS),我们就赢了。

解决方案

所以我们正在寻找解决方法。您可以使用 TS 文档 (https://github.com/google/clasp/blob/master/docs/typescript.md) 在 clasp 中找到一些,但还有一个我发现最简单的技巧:

在本地定义 var(不导出它),然后导出一个包含我们要导出的所有 var(当然也可以是函数)的对象。 TS 将表现为定期导出变量(它是 用于导出变量的语法糖),但编译器会将变量保存在全局变量和导出对象中。

例子

const a = 5;

function b() {
   return 'Hello World';
}

export {
   a,
   b
}

这样,变量就真正导出了,可以像往常一样在 TS 中使用,但在编译为 GAS 文件后也会留在全局环境中(编译器实际上会将它们添加到 export 对象中,但我们不应该关心它)。