Skip to content

Instantly share code, notes, and snippets.

@chrisrzhou
Last active February 26, 2020 00:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisrzhou/1acb9f0d775b20ef71b69af2ad81be3d to your computer and use it in GitHub Desktop.
Save chrisrzhou/1acb9f0d775b20ef71b69af2ad81be3d to your computer and use it in GitHub Desktop.
Typescript notes

Main resource: https://basarat.gitbook.io/typescript/

  • Typescript is a superset of Javascript. The type system in Typescript is designed to be optional so that your Javascript is Typescript. It does not block Javascript emit in the presence of type errors, allowing users to progressively update JS to TS.
  • Upgrading to TS without anyone noticing: https://devblogs.microsoft.com/typescript/how-to-upgrade-to-typescript-without-anybody-noticing-part-1/
  • Migrating JS -> TS
    • Add a tsconfig.json.
    • Convert files from .js to .ts. Suppress errors using any.
    • Write new code in TS avoiding using any.
    • Go back to old code and start adding type annotations and fixing bugs.
    • Use ambient definitions for third party JS code.
  • Make use of readonly and Readonly, ReadonlyArray etc features.
  • I find it simplest to always be explicit about function returns. After all, these annotations are a theorem and the function body is the proof.

  • You can use any prefix for generics, but it's common to use T, based on templates in C.
  • Use ambient definitions in declaration files *.d.ts to suppress typescript errors in third party code. This can also be used for non-JS imports e.g. declare module "*.css"
  • lib.d.ts includes declarations for most core JS interfaces and variables. You can edit this in compilerOptions and supply additional libs (e.g. dom, es6).
  • DO NOT throw raw strings for errors. They become difficult to debug, always try to use the right errors. In fact, it's better to pass the error object itself around with callback (node does this).
  • If a file has the extension .d.ts, then each root level definition must have the declare keyword prefixed to it. Use an interface whenever possible instead of simply declaring any.
  • Use module: commonJs in tsconfig.json
  • Study Promise.
  • Study async/await and understand how they use generators (function*) under the hood.
  • Typescript has concept of "type declaration space" (interface, class, type) and "variable declaration space" (class, var, let, const etc).
  • Modules are looked up in order of foo.js, foo/index.js, foo/package.json (main or types field).
  • If we declare a module globally in global.d.ts, they will appear magically to that path. Prefer file-based modules for this though.
  • Recommended style guide: https://basarat.gitbook.io/typescript/styleguide
    • Don't prefix interfaces with I*
    • Use PascalCase for Enum, Class, Interface and camelCase for everything else.
    • Name files with camelCase.
    • Prefer [] instead of Array<> syntax for arrays.
  • If we need to emit JS, make sure the imported variables/types are actually used in code.
  • Avoid circular dependencies.
  • Avoid type assertions.
  • Avoid namespace. Use external modules instead.
  • enums are numeric by nature. They are self-incrementing, so make use of number enums as flags (i.e. assign None enum key to the first entry so you can use it for falsy checks!): https://basarat.gitbook.io/typescript/type-system/enums#number-enums-as-flags
  • Use interface if you have types with hierarchies, allowing access to implements and extends. Use type alias (i.e. type Foo = string | Bar to provide semantic names, allowing easy setup with unions or intersections.
  • Explore dynamic import expressions in various projects.
  • npm install and yarn add only installs non-dev dependencies. If using @types/* modules, install these as devDependencies.
  • Avoid export default: poor discoverability, error-prone refactors, cumbersome re-export syntax.
  • Turn on noImplicitAny and strictNullChecks.
  • Use the ! non-null assertion + definite assignment assertion operators in applicable places.
  • Use barrels (i.e. re-exporting interfaces into a common MyModule/index.js). You can collect named exports into a variable and export that variable to expose the object of methods instead: https://basarat.gitbook.io/typescript/main-1/barrel
  • Authoring typescript libraries: https://basarat.gitbook.io/typescript/library
  • jest has good typescript support: https://basarat.gitbook.io/typescript/intro-1/jest. Run it in --watch mode.
  • Mapped types are useful. You can also use keyof and typeof vocabulary terms.
    type Index = 'a' | 'b' | 'c';
    type FromIndex = { [k in Index]?: number }
    
    const colors = {
      red: 'reddish',
      blue: 'bluish',
    };
    type Colors = keyof typeof colors;
    let color: Colors;
    
  • React types in detail: https://basarat.gitbook.io/typescript/tsx/react
  • At any time we do not have typescript types, we can declare these globally in the respective namespace for Typescript to pick up:
declare global {
  namespace JSX {
    interface IntrinsicElements {
      'my-awesome-slider': MyAwesomeSliderProps;
    }

    interface MyAwesomeSliderProps extends React.Attributes {
      name: string;
    }
  }
}
  • Briefly how typescript works:
    • SourceCode ~~ scanner ~~> Token Stream ~~ parser ~~> AST ~~ binder ~~> Symbols
    • AST + Symbols ~~ checker ~~> Type Validation
    • AST + Checker ~~ emitter ~~> JS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment