Skip to content
GitHub LinkedIn

How to write an Alexa Skill in TypeScript

Recently, I have been gotten into Alexa skill development. In a nutshell, an Alexa skill is just a Lambda function that is triggered by an Alexa request referred to as an "intent" which you define in your intent model. Different "handlers" are then setup to perform the intended actions and respond appropriately. You can write your handlers in JavaScript, Python, or Java. I am not the most familiar with Python or Java, so I decided to write my skill in JavaScript.

However, I missed the type safety, developer experience, and built in documentation that TypeScript provides. So, I decided to rewrite my skill in TypeScript. Unfortunately, I found that there was not a lot of documentation on how to do this. (If you know of any, please let me know!) But, I know that TypeScript is JavaScript at the end of the day therefor it should be possible in theory. I just had to figure out how to do it. After a lot of trial and error, I finally got it working. Here is how I did it.

Before we get started, big shout out to this forum post where the last responded provided the key piece of information I needed to get this working.

Prerequisites

  • An Alexa Developer account
  • An Alexa Skill that you have already created for the Node environment I will not be covering how to create an Alexa Skill in this post. If you need help with that, check out this tutorial.

Step 1: Install TypeScript to your project

Navigate to the lambda directory of your project and run the following command:

npm install typescript

Note: I am adding TypeScript as a standard dependency because the Ask pipeline always runs npm install --production before deploying your code. If you add TypeScript as a dev dependency, it will not be installed when your code is compiled which will make your deploy fail.

Step 2: Create a tsconfig.json file

Run tsc --init to create a tsconfig.json file. This file will tell the TypeScript compiler how to compile your code. I recommend using the following settings:

{
  "compilerOptions": {
    "alwaysStrict" : true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "target": "es2017",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "composite": true,
    "noUnusedLocals": false,
    "skipLibCheck": true,
    "noUnusedParameters": false,
    "allowSyntheticDefaultImports": true
  }, 
  "include": [
    "src/**/*"
  ],
  "exclude": ["node_modules"]
}

Step 3: Create a [object Object] directory

From what I can tell, the Alexa deploy job will only look for an index.js file in the lambda directory as the entry point for your Lambda function. However, we want our source code to all be in TypeScript, including our TS compiler entry point index.ts file. So, we need to create a src directory to hold all of our TypeScript files. My file structure looks like this:

// Within the lambda directory
└───src
    ├───handlers
    │   ├───customHandlers
    │   ├───defaultHandlers
    │   └───index.ts
    │───utils
    │───index.js
    │───package.json
    └───tsconfig.json

Note: There will be a dist directory next to src in the lambda directory as well, but that will be created when we compile our TypeScript code.

Step 4: Tell index.js to look for the compiled index.js file

As I said before, the Alexa deploy job will only look for an index.js file in the lambda directory as the entry point for your Lambda function. So, we need to essentially use that file as a proxy to our compiled index.js file in the dist directory. To do this, we need to add the following code to the index.js file in the lambda directory:

const skill = require('./dist/index');
exports.handler = skill.handler;

Step 5: Compile your TypeScript code and cleanup on deploy

Now that we have everything setup, we need to setup our deploy job to compile our TypeScript code and cleanup after itself. To do this, we need to add the following to the package.json file.

"scripts": {
    "clean": "npx rimraf ./dist ./tsconfig.tsbuildinfo",
    "postinstall": "npm run clean && npm run build",
    "compile": "tsc --build tsconfig.json --pretty",
    "test": "jest --coverage",
    "build": "npm run compile"
}

I am not 100% sure if the clean or postinstall scripts are necessary, but I added them just in case at the recommendation of the last answer in the forum post I mentioned earlier. I also added a test script because I am using Jest for unit testing. You can add whatever scripts you need to this file.

And I believe that is it! You should now be able to write your Alexa Skill in TypeScript.

Other helpful tips

  • Sometimes your changes do not always get fully uploaded and deployed when you push to master. If you are having trouble getting your changes to show up, try updating the package version in the package.json file. This seems to guarantee that your changes will be deployed.
  • Install the @types/aws-sdk and @types/node packages to get type definitions for the AWS SDK and Node.js.
  • Eat red meat and work out. It's good for you. 🐄