Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Our Journey to TypeScript

Our Journey to TypeScript

Milano TS

May 04, 2018
Tweet

More Decks by Milano TS

Other Decks in Technology

Transcript

  1. const Gender = t.enums.of(['Male', 'Female'], 'Gender') const URL = t.refinement(t.String,

    (s) => s.startsWith('http'), 'URL') @props({ name: t.String, // a required string surname: t.maybe(t.String), // an optional string age: t.Number, // a required number gender: Gender, // an enum avatar: URL // a refinement }) class Card extends React.Component { render() { return ( <div> <p>{this.props.name}</p> ... </div> ) }
  2. But… Flow had some major issues ➔ Not intrusive :)

    Supported by Babel: It’s enough to add a tag ➔ Community :( Not involved in the development ➔ Core team :( Facebook and community goals seemed to diverge We were afraid of choosing a language doomed to be forgotten or confined in its niche
  3. ➔ Community :) Deeply involved in the development. A lot

    of typings for third-party libraries ➔ Core team :) The project looks stable and Microsoft’s goals are aligned with the ones of the community ➔ Better React support :O It’s a win!
  4. Analysis TS migration April 2017 Identify JS-to-TS critical points in

    our stack Identify a project able to support the cost of the experiment (time and budget) May 2017 JS to TS! Start of the code migration July 2017 Evaluation of the experiment. Do we like TypeScript? The TypeScript Experiment
  5. Project setup How can JavaScript and TypeScript live together for

    months? Do we have to rewrite our internal libraries before being able to test TypeScript on the project?
  6. Your build must support Babel and TypeScript The project will

    keep having some JavaScript code for months. TypeScript and Babel use different transpilers: in our tests TypeScript transpiled some code differently than Babel!
  7. const person: Person = { firstName: 'Francesco', lastName: 'Cioria' };

    // Webpack: TypeScript transpilation const tsTranspiler = [{ test: /\.tsx?$/, use: [{ loader: 'babel-loader' }, { loader: 'ts-loader' // uses tsconfig.json }], include: [paths.SRC] }]; const person = { firstName: 'Francesco', lastName: 'Cioria' }; var person = { firstName: 'Francesco', lastName: 'Cioria' }; // tsconfig.json { "compilerOptions": { "target": "esnext", // remove types "allowJs": true, "jsx": "react", ... } ... }
  8. You can quickly add a TypeScript interface to any JavaScript

    code Not a lot of libraries natively support TypeScript, but thanks to DefinitelyTyped and the .d.ts interfaces, you can use them as if they were written in TypeScript
  9. import * as React from 'react'; export type ButtonState =

    'ready' | 'not-allowed' | 'processing' | 'error' | 'success'; export type ButtonType = 'default' | 'primary' | 'positive' | 'negative' | 'flat'; export type ButtonSize = 'tiny' | 'small' | 'medium'; export type ButtonProps = { onClick: (e: React.SyntheticEvent<HTMLDivElement>) => void, buttonState?: ButtonState, label?: string | { [key in ButtonState]: string }, icon?:string | { [key in ButtonState]: string }, children?: string, type?: ButtonType, primary?: boolean, flat?: boolean, size?: ButtonSize, fluid?: boolean, circular?: boolean, style?: React.CSSProperties, className?: string } declare const Button: React.ComponentClass<ButtonProps>; export default Button;
  10. Let’s rewrite our project in TypeScript Starting where? Also, we

    cannot afford to pause the development...
  11. This is an experiment! The goal is not to rewrite

    the project as quickly as possible, but to evaluate its outcome. Leaf-components first: 1. Data management is harder to type 2. Complex containers are easier to type if all their children are typed 3. Leaf-components: many, small and isolated. Developers can work on them in parallel (knowledge share!) LE M O N
  12. const Gender = t.enums.of(['Male', 'Female'], 'Gender') @props({ name: t.String, //

    a required string surname: t.maybe(t.String), // an optional string age: t.Number, // a required number gender: Gender // an enum }) class Card extends React.Component { render() { return ( <div> <p>{this.props.name}</p> ... </div> ) } type Gender = 'Male' | 'Female'; type Props = { name: string, // a required string surname?: string, // an optional string age: number, // a required number gender: Gender // an enum } class Card extends React.Component<Props> { render() { return ( <div> <p>{this.props.name}</p> ... </div> ) }
  13. The experiment is successful! But our project still uses a

    lot of JavaScript and all our internal libraries are 100% JavaScript (with .d.ts interfaces)
  14. A new journey begins TypeScript adopted as primary language: •

    Started backporting it on our internal tools • Completed migration of pilot project • Every new project uses TypeScript by default • Started backporting on active projects
  15. ➔ VSCode :) It works great with TypeScript ➔ Types

    are first of all documentation :) Code is easier to read ➔ We tend to write better code Because it’s easier to represent good code with types ➔ Union types To represent only consistent states Unexpected things we liked
  16. Union Types to represent only consistent state [ts] Argument of

    type '{ view: "product"; }' is not assignable to parameter of type 'View'. Type '{ view: "product"; }' is not assignable to type '{ view: "product"; productId: number; }'. Property 'productId' is missing in type '{ view: "product"; }'.
  17. ➔ TSLint ESLint has a stronger community ➔ Types for

    third-party libraries Often incomplete or with mistakes ➔ Typing complex dynamic logic is difficult Of course, you shouldn’t write code like that… but every project has at least one example of that! Things to improve