Section 3: Misc. Concerns

Sometimes writing React isn't just about React. While we don't focus on other libraries like Redux (see below for more on that), here are some tips on other common concerns when making apps with React + TypeScript.

Writing TypeScript Libraries instead of Apps

propTypes may seem unnecessary with TypeScript, especially when building React + TypeScript apps, but they are still relevant when writing libraries which may be used by developers working in Javascript.

interface IMyComponentProps {
autoHeight: boolean;
secondProp: number;
}
export class MyComponent extends React.Component<IMyComponentProps, {}> {
static propTypes = {
autoHeight: PropTypes.bool,
secondProp: PropTypes.number.isRequired,
};
}

Something to add? File an issue.

Commenting Components

TypeScript uses TSDoc, a variant of JSDoc for TypeScript. This is very handy for writing component libraries and having useful descriptions pop up in autocomplete and other tooling (like the Docz PropsTable). The main thing to remember is to use /** YOUR_COMMENT_HERE */ syntax in the line just above whatever you're annotating.

import React from "react";
interface MyProps {
/** Description of prop "label".
* @default foobar
* */
label?: string;
}
/**
* General component description in JSDoc format. Markdown is *supported*.
*/
export default function MyComponent({ label = "foobar" }: MyProps) {
return <div>Hello world {label}</div>;
}

View in the TypeScript Playground

Something to add? File an issue.

Namespaced Components

Often when creating similar components or components that have a parent-child relationship, it is useful to namespace your components. Types can easily be added be using Object.assign();

import React from "react";
const Input = (props: any) => <input {...props} />;
const Form = React.forwardRef<HTMLDivElement, any>(
({ children, ...otherProps }, ref) => (
<form {...otherProps} ref={ref}>
{children}
</form>
)
);
/**
* Exported components now can be used as `<Form>` and `<Form.Input>`
*/
export default Object.assign(Form, { Input: Input });

View in the TypeScript Playground

(Contributed by @bryceosterhaus, see further discussion)

Something to add? File an issue.

Design System Development

I do like Docz which takes basically 1 line of config to accept TypeScript. However it is newer and has a few more rough edges (many breaking changes since it is still < v1.0)

For developing with Storybook, read the docs I wrote over here: https://storybook.js.org/configurations/typescript-config/. This includes automatic proptype documentation generation, which is awesome :)

Something to add? File an issue.

Migrating From Flow

You should check out large projects that are migrating from flow to pick up concerns and tips:

Useful libraries:

If you have specific advice in this area, please file a PR!

Something to add? File an issue.

Prettier

There isn't any real secret to Prettier for TypeScript. But its a great idea to run prettier on every commit!

$ yarn add -D prettier husky lint-staged
// inside package.json
{
//...
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"linters": {
"src/*.{ts,tsx,js,jsx,css,scss,md}": [
"prettier --trailing-comma es5 --single-quote --write",
"git add"
],
"ignore": ["**/dist/*, **/node_modules/*"]
}
},
"prettier": {
"printWidth": 80,
"semi": false,
"singleQuote": true,
"trailingComma": "es5"
}
}

Integrating this with ESlint may be a problem. We haven't written much on this yet, please contribute if you have a strong opinion. Here's a helpful gist.

For library authors, this is set up for you in tsdx. You may also wish to check out the newer https://ts-engine.dev/ project.

Testing

Yes, you can test your types! You shouldn't use it for EVERYTHING, but it can help prevent regressions:

Working with Non-TypeScript Libraries (writing your own index.d.ts)

Lets say you want to use de-indent, but it isn't typed or on DefinitelyTyped. You get an error like this:

[ts]
Could not find a declaration file for module 'de-indent'. '/Users/swyx/Work/react-sfc-loader/node_modules/de-indent/index.js' implicitly has an 'any' type.
Try `npm install @types/de-indent` if it exists or add a new declaration (.d.ts) file containing `declare module 'de-indent';` [7016]

So create a .d.ts file anywhere in your project with the module definition:

// de-indent.d.ts
declare module "de-indent" {
function deindent(): void;
export = deindent; // default export
}
Further Discussion

Any other tips? Please contribute on this topic! We have an ongoing issue here with some references. We have more discussion and examples in our issue here.

Compilation Speed

Compiling large TS projects can get slow. Here are some tips:

  • use TS 3.0 Project references
  • Webpack (see CRA diff):
    • set output.pathinfo = false
    • set optimization.splitChunks, optimization.removeAvailableModules, optimization.removeEmptyChunks to false