Using TypeScript in a Phoenix Project

For the last two year’s I have been working mostly with Typescript when developing for the front-end and it has fast become my preferred default. Unfortunately Typescript is not part of the default setup when starting a new project with the Elixir Phoenix Framework, so there are some steps I regularly have to go through to setup Typescript in a new Phoenix project.

mix phx.new my_app

cd my_app/assets

npm install

npm install --save-dev typescript @babel/preset-typescript eslint eslint-config-prettier eslint-plugin-prettier prettier @typescript-eslint/parser @typescript-eslint/eslint-plugin

Once we have installed TypeScript and a few other necessities you will then need to add tsconfig.json and a tslint.json configuration files.

// my_app/assets/tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    // Search under node_modules for non-relative imports.
    "moduleResolution": "node",
    // Process & infer types from .js files.
    "allowJs": true,
    // Don't emit; allow Babel to transform files.
    "noEmit": true,
    // Enable strictest settings like strictNullChecks & noImplicitAny.
    "strict": true,
    // Disallow features that require cross-file information for emit.
    "isolatedModules": false,
    // Import non-ES modules as default imports.
    "esModuleInterop": true
  },
  "include": ["src"]
}
// my_app/assets/tslint.json
{
  "rulesDirectory": ["tslint-plugin-prettier"],
  "extends": ["tslint-config-prettier"],
  "rules": {
    "prettier": true
  }
}

Then we need to tell Babel to use the Typescript preset by adding @babel/preset-typescript to your .babelrc file. Then it should look like below:

// my_app/assets/.babelrc
{
  "presets": ["@babel/preset-env", "@babel/preset-typescript"]
}

Typescript files use a .ts file extension, so we need to change the default Phoenix .js files over to use this extension. Also while making this change I rename the js directory to src.

You should then have a structure in your assets directory like below (some files omitted for brevity).

- css
- node_modules
- src
  - app.ts
  - socket.ts
- static
- vendor

Then lastly we need to make a few changes to the Webpack configuration so it is aware of the news files and structure. First we need to change the entrypoint to use our new src directory and app.ts file.

{
  entry: {
      './src/app.ts': ['./src/app.ts'].concat(glob.sync('./vendor/**/*.js'))
  },
}

Then we need to update the Babel loader to transpile files with a .ts extension.

{
  test: /\.ts$/,
  exclude: /node_modules/,
  use: {
    loader: 'babel-loader'
  }
}

Then you can fire up your Phoenix application with mix phx.server and you are ready to write your client side functionality in Typescript. You can check your up and running with a simple typed function like below, which Phoenix should then live-reload and display the prompt.

const say = (message: string) => alert(message);

say("Hello world!");
Ben Barber

Written by Ben Barber

A software engineer and data-driven trader from Cambridge, UK. Currently working full-time on developing trading algorithms for the US equity and options markets.

Don't miss the next post!

Subscribe to get future posts via email

Add your email address below to get notified when I publish new posts.

No spam ever. Unsubscribe anytime.