Migrating my React (create-react-app) application to Typescript
1 – Installing Typescript
Assuming that we created the project using create-react-app, now we have to install Typescript.
You can install it running this command:
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
2 – Add the tsconfig.json.
Just run this command:
npx tsc --init
The presence of a
tsconfig.json
file in a directory indicates that the directory is the root of a TypeScript project. Thetsconfig.json
file specifies the root files and the compiler options required to compile the project.JavaScript projects can use a
jsconfig.json
file instead, which acts almost the same but has some JavaScript-related compiler flags enabled by default.https://www.typescriptlang.org/docs/handbook/tsconfig-json.html
3 – Rename any component,
For example Button.js -> Button.tsx
Then run npm start
and you will see a message like that:
> react-scripts start
The following changes are being made to your tsconfig.json file:
- compilerOptions.lib to be suggested value: dom,dom.iterable,esnext (this can be changed)
- compilerOptions.allowJs to be suggested value: true (this can be changed)
- compilerOptions.allowSyntheticDefaultImports to be suggested value: true (this can be changed)
- compilerOptions.module must be esnext (for import() and import/export)
- compilerOptions.moduleResolution must be node (to match webpack resolution)
- compilerOptions.resolveJsonModule must be true (to match webpack loader)
- compilerOptions.isolatedModules must be true (implementation limitation)
- compilerOptions.noEmit must be true
- compilerOptions.jsx to be suggested value: react (this can be changed)
- include should be src
If you are using Windows and it gives you a error message like that…
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
Just run this command below. It is a workaround to fix heap out of memory when running node binaries (which is a common issue when using TypeScript 2.1+ and webpack) is increasing the max memory for node.
set NODE_OPTIONS=--max_old_space_size=8192
4 – Now we have to change our Button.tsx to Typescript
Before:
import React from 'react';
import BaseIcon from '../Icons/BaseIcon';
import './Button.scss';
export default function Button({
id,
label,
icon,
ariaLabel,
size,
colorHover,
onClick,
children,
role,
}) {
return (
<button
id={id || null}
type="button"
aria-label={ariaLabel || label || children}
name={label || children}
className={`button button-default color-${colorHover || 'default'} ${
icon && 'has-icon'
} size-${size || 'md'}`}
onClick={onClick}
role={role || null}
>
<span className={label || children ? 'has-label' : 'no-label'}>
{label || children}
{icon && <BaseIcon icon={icon} color="purple" />}
</span>
</button>
);
}
After:
import React, { MouseEventHandler, ReactNode, } from 'react';
import BaseIcon from '../Icons/BaseIcon';
import './Button.scss';
type Props = {
id: string,
label: string,
icon: string,
ariaLabel: string,
size: string,
colorHover: string,
role: string,
onClick: MouseEventHandler,
children: ReactNode,
}
export default function Button({
id,
label,
icon,
ariaLabel,
size,
colorHover,
onClick,
children,
role,
}: Props) {
return (
<button
id={id || undefined}
type="button"
aria-label={ariaLabel || label}
name={label || undefined}
className={`button button-default color-${colorHover || 'default'} ${
icon && 'has-icon'
} size-${size || 'md'}`}
onClick={onClick}
role={role || undefined}
>
<span className={label || children ? 'has-label' : 'no-label'}>
{label || children}
{icon && <BaseIcon icon={icon} color="purple" />}
</span>
</button>
);
}
5 – Convert all files to Typescript
It can be lots of work but it will be worth. If the project you’re migrating is rather large, I suggest doing this over multiple iterations. Otherwise, you may tire yourself out.
During this step, you may need to add additional packages depending on what third-party libraries you’re using. For instance, I am using moment so I had to run yarn add -D @types/moment to add the types as a devDependency.