Introduce TypeScript to react(js) project with ts-migrate๐
0xkoji
Posted on September 8, 2020
TypeScript has been getting popular since it makes js codebase legit.
Dropbox did a huge migration!!! This is worth reading.
The Great CoffeeScript to Typescript Migration of 2017
https://dropbox.tech/frontend/the-great-coffeescript-to-typescript-migration-of-2017
Last month Airbnb released a really interesting package.
Learn about how we used codemods to accelerate migration from JavaScript to TypeScript at Airbnb. https://t.co/s1WihkfD1F
โ Airbnb Engineering (@AirbnbEng) August 18, 2020
In this article, I would like to introduce a small case that I tried.
Create a new branch
git checkout -b feature/ts-migrate
# you can use `switch` if your git version is later 2.23
git switch feature/ts-migrate
Install ts-migrate
$ yarn add -D ts-migrate
# or
$ npm install --save-Dev ts-migrate
Run ts-migrate
In this step, we need to avoid using yarn
since there is an issue, so we need to use npx
.
The issue has been fixed(https://github.com/airbnb/ts-migrate/commit/50f1a6cbc08c241c7f6ce822ca999cb197ae1e92)
So, npx
and yarn
, both of them are working.
In this article, the target folder is src
$ npx ts-migrate-full src
Welcome to TS Migrate! :D
This script will migrate a frontend folder to a compiling (or almost compiling) TS project.
It is recommended that you take the following steps before continuing...
1. Make sure you have a clean git slate.
Run `git status` to make sure you have no local changes that may get lost.
Check in or stash your changes, then re-run this script.
2. Check out a new branch for the migration.
For example, `git checkout -b koji--ts-migrate` if you're migrating several folders or
`git checkout -b koji--ts-migrate-src` if you're just migrating src.
3. Make sure you're on the latest, clean master.
`git fetch origin master && git reset --hard origin/master`
4. Make sure you have the latest npm modules installed.
`npm install` or `yarn install`
If you need help or have feedback, please file an issue on Github!
Continue? (y/N)
before
Set a custom path for the typescript compiler. (It's an optional step. Skip if you don't need it. Default path is ./node_modules/.bin/tsc.):
Your default tsc path is ./node_modules/.bin/tsc.
[Step 1 of 4] Initializing ts-config for the "src"...
Config file created at /Users/koji/Documents/github/React-Hooks-StarterFiles/react-hooks-videoplayer/src/tsconfig.json
[test/ts 2249a33] [ts-migrate][src] Init tsconfig.json file
2 files changed, 69 insertions(+)
create mode 100644 src/.eslintrc
create mode 100644 src/tsconfig.json
/Users/koji/Documents/github/React-Hooks-StarterFiles/react-hooks-videoplayer
[Step 2 of 4] Renaming files from JS/JSX to TS/TSX and updating project.json\...
Renaming 21 JS/JSX files in /Users/koji/Documents/github/React-Hooks-StarterFiles/react-hooks-videoplayer/src...
Done.
[test/ts d5675b0] [ts-migrate][src] Rename files from JS/JSX to TS/TSX
21 files changed, 0 insertions(+), 0 deletions(-)
rename src/components/{Darkmode.js => Darkmode.tsx} (100%)
rename src/components/{PlaylistHeader.js => PlaylistHeader.tsx} (100%)
rename src/components/{PlaylistItem.js => PlaylistItem.tsx} (100%)
rename src/components/{Video.js => Video.tsx} (100%)
rename src/components/containers/{App.js => App.tsx} (100%)
rename src/components/containers/{Playlist.js => Playlist.tsx} (100%)
rename src/components/containers/{PlaylistItems.js => PlaylistItems.tsx} (100%)
rename src/components/containers/{WbnPlayer.js => WbnPlayer.tsx} (100%)
rename src/components/hoc/{withLink.js => withLink.tsx} (100%)
rename src/components/styles/{GlobalStyle.js => GlobalStyle.ts} (100%)
rename src/components/styles/{StyledDarkmode.js => StyledDarkmode.ts} (100%)
rename src/components/styles/{StyledJourney.js => StyledJourney.ts} (100%)
rename src/components/styles/{StyledPlaylist.js => StyledPlaylist.ts} (100%)
rename src/components/styles/{StyledPlaylistHeader.js => StyledPlaylistHeader.ts} (100%)
rename src/components/styles/{StyledPlaylistItem.js => StyledPlaylistItem.ts} (100%)
rename src/components/styles/{StyledPlaylistitems.js => StyledPlaylistitems.ts} (100%)
rename src/components/styles/{StyledVideo.js => StyledVideo.ts} (100%)
rename src/components/styles/{StyledVideoWrapper.js => StyledVideoWrapper.ts} (100%)
rename src/components/styles/{StyledWbnPlayer.js => StyledWbnPlayer.ts} (100%)
rename src/{index.js => index.tsx} (100%)
rename src/{serviceWorker.js => serviceWorker.ts} (100%)
/Users/koji/Documents/github/React-Hooks-StarterFiles/react-hooks-videoplayer
[Step 3 of 4] Fixing TypeScript errors...
forkTSServer
Logs in /var/folders/gj/x6v5vwdx1v7741fdfcxwmr100000gn/T/ts-migrate-log-iiAQGO
TypeScript version: 3.9.7
Initialized tsserver project in 207.623ms.
Start...
[strip-ts-ignore] Plugin 1 of 12. Start...
[strip-ts-ignore] Finished in 53.092ms.
[hoist-class-statics] Plugin 2 of 12. Start...
[hoist-class-statics] Finished in 25.675ms.
[react-props] Plugin 3 of 12. Start...
[react-props] Finished in 15.874ms.
[react-class-state] Plugin 4 of 12. Start...
[react-class-state] Finished in 1.483ms.
[react-class-lifecycle-methods] Plugin 5 of 12. Start...
[react-class-lifecycle-methods] Finished in 10.154ms.
[react-default-props] Plugin 6 of 12. Start...
[react-default-props] Finished in 0.768ms.
[react-shape] Plugin 7 of 12. Start...
[react-shape] Finished in 0.989ms.
[declare-missing-class-properties] Plugin 8 of 12. Start...
[declare-missing-class-properties] Finished in 1517.982ms.
[explicit-any] Plugin 9 of 12. Start...
[explicit-any] Finished in 363.076ms.
[eslint-fix] Plugin 10 of 12. Start...
[eslint-fix] Finished in 1148.936ms.
[ts-ignore] Plugin 11 of 12. Start...
[ts-ignore] Finished in 370.630ms.
[eslint-fix] Plugin 12 of 12. Start...
[eslint-fix] Finished in 193.324ms.
Finished in 3703.120ms, for 12 plugin(s).
Writing 21 updated file(s)...
Wrote 21 updated file(s) in 3.488ms.
rm: src/.eslintrc.*: No such file or directory
If everything goes well, ts-migrate
will convert .js
files to .ts
and .tsx
. In addition, create tsconfig.json
and .eslintrc.js
after
Note:tsconfig.json
and .eslintrc.js
are generated under src
.
Install typescript and @types files
If ts-migrate
did this step automatically, that would be amazing, but actually, right now it doesn't. We need to install typescript
and @types
files.
If there is no @type file, you will need to create global.d.ts
for packages that don't support typescript.
$ yarn add -D typescript
Install ts-loaderwebpack.config.js
The react app I used in this article uses webpack to bundle .js
files. The project needs ts-loader
to support typescript.
Now, it's time to open src
folder with an editor. I use Visual Studio Code.
Remove ts-something
ts-migrate
has put ts-error
and ts-migrate(7016) FIXME
to avoid errors.
Most cases will be solved by installing @types files for npm packages so what we need to do is to remove comments.
Modify webpack.config.js
This project is using webpack to bundle js files, but now files are .ts
, or .tsx
so need to modify webpack configurations a little bit.
The most important thing is to switch from .js
to .tsx
or .ts
For example, entry
, extensions
and using ts-loader
etc.
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
const autoprefixer = require('autoprefixer');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/index.tsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
chunkFilename: '[id].js',
publicPath: '',
},
devtool: 'inline-source-map',
devServer: {
contentBase: './',
open: true,
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
},
// {
// test: /\.(gif|png|svg|jpg)$/,
// loader: "url-loader"
// },
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
exclude: /node_modules/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]___[hash:base64:5]',
},
sourceMap: true,
},
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [autoprefixer({})],
},
},
],
},
{
test: /\.(svg|png|jpe?g|gif)$/,
loader: 'url-loader?limit=10000&name=img/[name].[ext]',
},
],
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.json'],
},
plugins: [
new HtmlWebpackPlugin({
template: __dirname + '/public/index.html',
filename: 'index.html',
inject: 'body',
}),
],
};
Update npm script
I just added .ts
and .tsx
as a target file like below.
"scripts": {
...
"lint": "eslint 'src/**/*.{ts,tsx}'",
"lint:prettier": "prettier --check './src/**/*.{js,ts,tsx}'"
}
Small modification
If you see some .tsx
or .ts
code, you notice that ts-migrate
just use any
for all variable which isn't good but it totally makes sense as a migration tool's behavior since ts-migrate
doesn't know about your project.
In this case, I know the project itself since I wrote this code recently which means I still remember the variables' types. So I updated any
to a proper data-type.
Conclusion
In my opinion, ts-migrate
is very useful. It will make a codebase legit and reduce the migration cost a little bit.
I think if you don't think that it's not time to do the migration, still trying ts-migrate
can be useful.
For example, I tried ts-migrate
for an open-source library which is written in javascript and saw a bug that a function defines 2 parameters, but it is given 3 parameters(of course, the extra one isn't used). You may find out this kind of issue on your codebase then you can back to js to fix the issues you detected lol.
Posted on September 8, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024
November 23, 2024
November 16, 2024