Skip to content

Instantly share code, notes, and snippets.

@mheiber
Last active January 24, 2019 02:41
Show Gist options
  • Save mheiber/c6d1b3b0c93168fdacaa47ee3124cac9 to your computer and use it in GitHub Desktop.
Save mheiber/c6d1b3b0c93168fdacaa47ee3124cac9 to your computer and use it in GitHub Desktop.
JSConf.Asia Autobang (JS->strict TS) Talk

Summary: I describe why and how we built "Autobang", a tool that automatically converts JS projects to strict TypeScript. This is an unusual solution to a problem that previously seemed intractable for large projects.

We built a tool to automatically convert a JS codebase to strict TypeScript with some interesting trade-offs. This is a hard and interesting problem I've never heard discussed

Why TypeScript

  • enables devs to express intent of code
  • dev tools
  • catch silly errors early

Why Strict TypeScript

  • enhanced expressivity, dev tooling
  • avoiding "cannot call method foo of 'undefined'" and similar runtime errors

Strict TypeScript

  • --strictNullChecks
  • --noImplicitAny
  • --noImplicitThis
  • --strictBindCallApply
  • --strictNullChecks
  • --strictPropertyInitialization
  • and more

Strict TypeScript Examples

--strictNullChecks

const arr = [1, 2, 3];
while (arr.length) {
    console.log(arr.pop() + 1); // Error
}

Strict TypeScript Examples

--noImplicitAny

const sum = (n1, n2) => n1 + n2; // error
sum({}, {});

Strict TypeScript Examples

--strictNullChecks --strictPropertyChecks

class Circle {
  diameter: number; // error

  constructor(diameter: number) {
    this.setUpDimensions(diameter);
  }

  setUpDimensions(diameter: number) {
    this.diameter = diameter;
  }
}

Goal and Constraints

Goal: convert a 2 million lines of JS to strict TS

Constraints

  • must be incremental
  • can't ever manually refactor all the code

Solutions

Goal: convert millions of lines of JS to strict TS

Unusualy Goal!

Bad Solutions:

  • JS --> manually convert to strict TS (manual)
  • JS --> loose TS (manual) --> strict TS (manual)

Weird Solution (ours, coming later)

Existing solutions for loose TS --> strict TS:

  • TS Team's solution
  • VS Code Team's solution

TS Team's Solution for Loose -> Strict TS

Mostly manual! Converted todo loc in todo weeks remaining "TODO"s where ! is used: todo

todo link to GitHub issue todo fact check

VS Code Team's solution

GH issue: microsoft/vscode#60565

2 tsconfigs:

  • main tsconfig (loose) actually compiles the project
  • supplementary tsconfig (strict) for type-checking subset of files

over time:

  • add more files to includes in supplementary tsconfig until all files checked

New Solution: Autobang

First convert JS to loose TypeScript:

  • rename files *.ts -> *.js
  • declare properties for classes

New Solution: Autobang

Then convert loose TS to strict TS:

  • tell TS compiler "I know what I'm doing"
  • teams can incrementally remove "todos"

Autobang: --noImplicitAny

  • tell TS compiler "I know what I'm doing"
type TODO = any
const sum = (n1: TODO, n2: TODO) => n1 + n2
  • teams can incrementally remove "todos"
type TODO = never

Autobang: --strictNullChecks

  • tell TS compiler "I know what I'm doing"
const arr = [1, 2, 3];
while (arr.length) {
    console.log(arr.pop() ! + 1); // Error
}

Note the bang: !

  • teams can incrementally remove "todos"

Find and remove all instances of ' !': %s/ !//g

Autobang Trade-offs

Good:

  • All new code is checked
  • Completely automated and fast
  • Relatively easy to add types incrementally

Autobang trade-offs

Bad:

  • Assertions cause us to miss obvious bugs!
type Dog = { bark(): void };
let fido: Dog;
fido !.bark(); // assertion hides the mistake

What's next

  • identify difference between "TS needs more info here" and "this is an obvious bug"
  • incorporate something like TypeWhiz into the workflow
  • identify portions of codebases most in need of manual typing

Discussion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment