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

TSConf 2019: Don't Break the Contract: Keep Consistency with Full Stack Type Safety

TSConf 2019: Don't Break the Contract: Keep Consistency with Full Stack Type Safety

We’ve seen the Web evolve from blue hyperlink text to complex web applications. In modern web application development, not only JavaScript is allowing our teams to build richer user experiences in the front-end, but Node.js has also emerged as the go-to back-end technology of choice.

While this stack is flexible and fun to program in, building and maintaining internal APIs can be an unpleasant experience. Have you ever had a front-end bug because there was an unexpected change in the back-end? In this talk, we’ll explore how TypeScript can help our development teams to reduce these bugs by extending the type system from the back-end to the front-end.

We'll discover how types bring benefits to an application in terms of maintainability, robustness, and clean code that can be easily refactored in the future.

Fernanda Andrade

October 11, 2019
Tweet

More Decks by Fernanda Andrade

Other Decks in Programming

Transcript

  1. Don’t Break the Contract:
    Full Stack Type Safety with TypeScript
    @feru @flandrade

    View Slide

  2. Consumer
    Provider
    Contract

    View Slide

  3. Contract

    View Slide

  4. {
    name: "Tess",
    price: 11
    }

    View Slide

  5. {
    name: "Tess",
    prices: [11, 9]
    }

    View Slide

  6. {
    name: "Tess",
    prices: [11, 9]
    }

    View Slide

  7. Contract
    Modify data
    structures

    View Slide

  8. How do we solve it?

    View Slide

  9. Integration tests

    View Slide

  10. Provider

    View Slide

  11. Provider Consumer

    View Slide

  12. Request
    Response
    Provider Consumer

    View Slide

  13. Integration tests are
    expensive
    slow
    reliable

    View Slide

  14. Contract tests

    View Slide

  15. Request
    Response
    Provider

    View Slide

  16. Request
    Response
    Provider
    Contract

    View Slide

  17. Request
    Response
    Consumer
    Contract

    View Slide

  18. Contract tests are
    less expensive
    less slow
    less reliable

    View Slide

  19. Types with
    Project References

    View Slide

  20. client
    tsconfig.json
    server
    tsconfig.json

    View Slide

  21. client
    tsconfig.json
    server
    tsconfig.json
    shared-types
    tsconfig.json
    (Contract)

    View Slide

  22. client
    tsconfig.json
    server
    tsconfig.json
    shared-types
    tsconfig.json

    View Slide

  23. client
    tsconfig.json
    server
    tsconfig.json
    shared-types
    tsconfig.json
    tsconfig.json (Solution)

    View Slide

  24. {
    "references": [
    {
    "path": "client"
    },
    {
    "path": "server"
    },
    {
    "path": "shared-types"
    }
    ],
    "files": []
    }
    tsconfig.json
    (Solution)

    View Slide

  25. {
    "extends": "../tsconfig.base.json",
    "compilerOptions": {
    ...
    }
    },
    "references": [
    { "path": "../shared-types" }
    ]
    }
    tsconfig.json
    (client)

    View Slide

  26. View Slide

  27. View Slide

  28. Types are the single
    source of truth

    View Slide

  29. declare namespace MyApi {
    type Status = "available" | "unavailable";
    interface User {
    age: number;
    id: number;
    name: string;
    status: Status;
    }
    interface GetUsers {
    (): Promise;
    }
    ...
    index.d.ts
    (shared-types)

    View Slide

  30. const getUsersReq = (req, res) => {
    res.json(getUsersFn());
    };
    const getUsersFn: GetUsers = function() {
    const users: User[] =
    [{
    age: 15,
    id: 10,
    name: "Tess",
    status: "available"
    }];
    return Promise.resolve(users);
    };
    users.ts
    (server)

    View Slide

  31. declare namespace MyApi {
    type Status = "available" | "unavailable";
    interface User {
    age: number;
    id: number;
    name: string;
    status: Status;
    }
    interface GetUsers {
    (): Promise;
    }
    ...
    index.d.ts
    (shared-types)

    View Slide

  32. const getUsersReq = (req, res) => {
    res.json(getUsersFn());
    };
    const getUsersFn: GetUsers = function() {
    const users: User[] =
    [{
    age: 15,
    id: 10,
    name: "Tess",
    status: "available"
    }];
    return Promise.resolve(users);
    };
    users.ts
    (server)

    View Slide

  33. declare namespace MyApi {
    type Status = "available" | "unavailable";
    interface User {
    age: number;
    id: number;
    name: string;
    status: Status;
    }
    interface GetUsers {
    (): Promise;
    }
    ...
    index.d.ts
    (shared-types)

    View Slide

  34. const getUsersReq = (req, res) => {
    res.json(getUsersFn());
    };
    const getUsersFn: GetUsers = function() {
    const users: User[] =
    [{
    age: 15,
    id: 10,
    name: "Tess",
    status: "available"
    }];
    return Promise.resolve(users);
    };
    users.ts
    (server)

    View Slide

  35. index.d.ts
    (shared-types)
    declare namespace MyApi {
    type Status = "available" | "unavailable";
    interface User {
    age: number;
    id: number;
    nickname: string;
    status: Status;
    }
    ...

    View Slide

  36. View Slide

  37. View Slide

  38. View Slide

  39. View Slide

  40. ✓ Contracts change with types
    ✓ Build fails if server and client don’t comply

    View Slide

  41. Logical separation
    between components

    View Slide

  42. client
    tsconfig.json
    server
    tsconfig.json
    shared-types
    tsconfig.json

    View Slide

  43. ✓ Separation of concerns
    ✓ Loosely-coupled packages
    ✓ No cross-referenced copied code

    View Slide

  44. No confusion
    about package version

    View Slide

  45. Write Publish
    Package A
    With dependencies
    Update Write
    Package B

    View Slide

  46. Write Publish
    Package A
    With project references
    Update Write
    Package B

    View Slide

  47. ✓ No need to publish a package
    ✓ No extra tools to handle versions

    View Slide

  48. Take advantage of your
    types

    View Slide

  49. View Slide

  50. Types are the single
    source of truth

    View Slide

  51. Thank you!
    @feru @flandrade

    View Slide