Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

☂️ Umbrella Issue: Adopting Typescript #606

Closed
22 tasks
zstix opened this issue Dec 8, 2021 · 1 comment
Closed
22 tasks

☂️ Umbrella Issue: Adopting Typescript #606

zstix opened this issue Dec 8, 2021 · 1 comment

Comments

@zstix
Copy link
Contributor

zstix commented Dec 8, 2021

Overview

This ticket represents the effort needed to evaluate and, potentially, transition the theme from Javascript to Typescript.

The original intention for using Javascript over Typescript for our Gatsby sites was to reduce the barrier to entry for contributors who wanted to write code. This decision was made well over a year ago and the codebase (and contributor) landscape looks much different now. The amount of components and custom code has grown significantly and it's possible that adding a typing system is now better for new contributors (better code hints and warnings). I've included three examples below to illustrate the point.

This will require us to touch the entire codebase, which has an additional benefit: we should be able to identify areas of the codebase that need to be refactored or consolidated.

Examples / Justification

Typescript in Gatsby is well supported. Most of the time, we should be able to simply replace a .js extension with .ts (or .tsx for components). Since typescript is a superset of Javascript, all of our code is valid typescript be default. Below is how we could also update the code to to take advantage of some of Typescripts features.

Example A: The <Callout> Component

For many of our components, we should be able to replace the Prop Types with an [interface](https://www.typescriptlang.org/docs/handbook/interfaces.html) to get the same benefits as prop-types, while also gaining better code completion hints and in-editor warnings.

Before

const Callout = ({ className, title, variant, children }) => {
  // ...
};

Callout.propTypes = {
  className: PropTypes.string,
  title: PropTypes.string,
  variant: PropTypes.oneOf(Object.values(Callout.VARIANT)).isRequired,
  children: PropTypes.node.isRequired,
};

Notice that, when using the component, there is no warning that we've passed in an invalid variant prop.

Screen Shot 2021-12-08 at 09 19 02

After

interface CalloutProps {
  className?: string;
  title?: string;
  variant: keyof typeof VARIANTS;
}

const Callout: React.FC<CalloutProps> = ({ className, title, variant, children }) => {
  // ...
};

With Typescript, we don't need to supply boilerplate types (such as children). While typing this out, VS Code gave me code completion for each prop and when I started typing variant it gave me all the possible variants as options (not something provided to before). Lastly, if I pass in an invalid variant, I get a very helpful warning:

Screen Shot 2021-12-08 at 09 22 12

Example B: The useClipboard hook

For simple hooks like `useClipboard`, VS Code already does a pretty good job of inferring the types. That said, by adding just a little bit of information about the return type, we can get much better type safety and code hints.

Before

const useClipboard = ({ duration = 100 } = {}) => {
  // ...
  return [copied, copy];
};

After

const useClipboard = ({ duration = 1000 } = {}): [boolean, (text: string) => void] => {
 // ...
  return [copied, copy];
};

Without typescript, we would not get this warning. Furthermore, we would not be able to know that copied is a boolean and copy is a function.

Screen Shot 2021-12-08 at 10 24 51

Example C: transformKeys helper function (more advanced)

For helper functions that are meant to work in an abstract / generalized way, we can take advantage of some more advanced features of Typescript to help newer contributors understand what they return.

Before

const transformKeys = (obj, fn) =>
  Object.keys(obj).reduce(
    (memo, key) => ({
      ...memo,
      [fn(key)]: key,
    }),
    {}
  );

We have zero idea what the result of this object looks like:

Screen Shot 2021-12-08 at 12 03 43

After

type Transformer = <T>(obj: T, fn: (key: string) => string) => { [Key: string]: keyof T };

const transformKeys: Transformer = (obj, fn) =>
  Object.keys(obj).reduce(
    (memo, key) => ({
      ...memo,
      [fn(key)]: key,
    }),
    {}
  );

Here we create a type for this function that utilizes some other features. While creating this might be a little tricky, we get a much more helpful description of what this returns. We know that the result will be an object, with the values equal to the keys of the input object (foo in the example screenshot below).

Screen Shot 2021-12-08 at 12 11 59

Process

This ticket is intended to be the umbrella / epic doc for this effort. The tasks below can be turned into implementation tickets as we see fit.

Phase 1: Research & Evaluation

  • Create umbrella ticket with examples
  • Review with the team
  • Decide whether or not to move forward with this effort
  • Refine tasks below as needed

Phase 2: Components

  • Simple components (those not in a sub-directory) converted
  • Dropdown components converted
  • Layout components converted
  • PageTools components converted
  • SearchModal components converted
  • Terminal components converted
  • Component tests converted

Phase 3: Hooks and Helpers

  • Hooks converted
  • Hook tests converted
  • Utils converted
  • Util tests converted

Phase 4: Gatsby-Specific Files

  • Pages converted
  • Gatsby function-specific files converted
  • gatsby-node.js converted

Phase 5: Wrap-up / Documentation

  • Remaining files converted
  • Types exported for use in Gatsby sites
  • Component documentation updated
  • Readme / runbook documentation updated
@jerelmiller
Copy link
Contributor

This is also a helpful resource for those less familiar with TypeScript: https://react-typescript-cheatsheet.netlify.app/

@jpvajda jpvajda removed this from Tentative next in Developer Enablement Team Mar 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants