使用 TypeScript 寫機器人

雖然本書是以 Node.js 為主要的程式開發語言,不過開發階段也可以使用 TypeScript,再將它編譯成 JavaScript 語法讓 Node.js 執行。這個範例說明幾個使用 TypeScript 的經驗與作法。

安裝 TypeScript 相關套件

可以安裝下列套件到 devDependencies 區段:

  • typescript: TypeScript 的編譯器及其相關工具。
  • ts-node: 可以用來直接執行 *.ts 檔案,它會自己編譯。
  • nodemon: 在開發階段的好用工具,它偵測到檔案修改後會重新執行 node 應用程式,加快開發測試的步驟。
  • @types/node: 讓 TypeScript 的工具(包含像是 Visual Studio Code)這樣的 IDE 環境可以知道 node 的資料型別。
  • (選擇性) @types/restify: 讓 TypeScript 的工具認認識 restify 的資料型別。
  • (選擇性) tslint: 想自虐的話可以裝這個工具檢查寫的 typescript 語法。

設定 TypeScript 編譯選項

要設定 TypeScript 的編譯行為,可以在目錄中加入一個 tsconfig.json 的檔案來進行設定,例如可以設定成這樣:

{
    "compilerOptions": {
        "target": "es6",
        "module": "commonjs",
        "moduleResolution": "node",
        "outDir": "./dist"
    },
    "files": [
        "app.ts"
    ]
}

這裡主要設定了幾個項目:

  • target: 設定在 TypeScript 中用的語法標準。
  • module: 設定產生模組的程式碼的語法標準。
  • moduleResolution: 設定用哪一種標準解析模組。可以參考這頁說明。
  • outDir: 設定編譯後產生的檔案要放在哪個目錄中。

更多的選項可以參考 TypeScript 的 Compiler Options 頁面說明。

設定常用且方便的 Scripts

因為是使用 TypeScript 做開發,最終還是要編譯過後再用 node 執行,所以可以新增幾個方便的 scripts 來簡化操作:

  • build: 要編譯 typescript 的程式碼的指令,最簡單就是執行 tsc 如果有其它的參數也可以加在這裡。
  • postinstall: 在執行完 npm install 指令後自動跑一次 npm run build 的指令讓它編譯一次。
  • satch: 使用 nodemon 搭配 ts-node 來執行 node 程式,ts 檔案一經修改就會自動重啟程式,在 debug 階段很有用。
  • start: 普通的啟動指令,先跑一次 build 確定都編譯了再執行。

所以 package.json 檔案內容可能會像這樣:

{
    "name": "my-ts-bot",
    "version": "1.0.0",
    "main": "app.js",
    "scripts": {
        "build": "tsc",
        "postinstall": "npm run build",
        "watch": "nodemon -x ts-node -- app.ts",
        "start": "npm run build && node dist/app.js"
    },
    "dependencies": {
        "botbuilder": "^3.8.4",
        "request": "^2.81.0",
        "restify": "^5.0.1"
    },
    "devDependencies": {
        "@types/node": "^8.0.15",
        "@types/request": "^2.0.0",
        "@types/restify": "^5.0.1",
        "nodemon": "^1.11.0",
        "ts-node": "^3.3.0",
        "tslint": "^5.5.0",
        "typescript": "^2.4.2"
    }
}

撰寫程式碼

以 2.3 的範例為例:讓使用者輸入一個關鍵字,然後在 Bing 搜尋相關的圖片,再回覆給使用者。

import * as builder from 'botbuilder';
import * as restify from 'restify';
import * as request from 'request';

const IMGSEARCH_URL: string = 'https://api.cognitive.microsoft.com/bing/v5.0/images/search'
const BING_KEY: string = process.env.BING_API_KEY;

let server: restify.Server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, () => {
    console.log('%s listening to %s', server.name, server.url);
});

let connector: builder.ChatConnector = new builder.ChatConnector({
    appId: process.env.MICROSOFT_APP_ID,
    appPassword: process.env.MICROSOFT_APP_PASSWORD
});
server.post('/api/messages', connector.listen());

let defaultDialog: builder.IDialogWaterfallStep = (session: builder.Session): void => {
    let msg: builder.IMessage = session.message;
    let postOpt: request.Options = {
            url: `${IMGSEARCH_URL}?q=${msg.text}`,
            method: 'POST',
            json: true,
            headers: {
                'Content-Type': 'application/json',
                'Ocp-Apim-Subscription-Key': BING_KEY
            }
        };

    session.sendTyping();

    request(postOpt, (error, response: request.RequestResponse, body: any): void => {
        // 建立回傳的訊息
        let retMsg: builder.Message = new builder.Message(session);
        let imgArr: Array<builder.HeroCard> = [];
        body.value.forEach((img: any) => {
            // 將資料製作成 Hero Card
            let imgCard: builder.HeroCard = new builder.HeroCard(session)
                            .title(img.name)
                            .images([builder.CardImage.create(session, img.thumbnailUrl)]);
            imgArr.push(imgCard);
        });

        retMsg.attachments(imgArr);
        retMsg.attachmentLayout(builder.AttachmentLayout.carousel);
        session.send(retMsg);
    });
};

let bot: builder.UniversalBot = new builder.UniversalBot(connector, defaultDialog);

加上一些型別的資訊,當使用支援 TypeScript 語法解析的 IDE (如: Visual Studio Code) 時就會有很好的語法提示效果。

參考資源

results matching ""

    No results matching ""