Cheatsheets for experienced React developers getting started with TypeScript
Basic | Advanced | Migrating | HOC | 中文翻译 | Español | Contribute! | Ask!
This Cheatsheet collates advice and utilities from real case studies of teams moving significant codebases from plain JS or Flow over to TypeScript. It makes no attempt to convince people to do so, but we do collect what few statistics companies offer up after their conversion experience.
⚠️ This Cheatsheet is extremely new and could use all the help we can get. Solid advice, results, and up to date content all welcome.
Read TypeScript's official Guide for migrating from JS and you should already be familiar with their React conversion guide.
- Level 0: Don't use TypeScript, use JSDoc
- See our JSDoc section
- Level 1A: Majority JavaScript, increasingly strict TypeScript
- as recommended by official TS guide
- use
allowJS
(Experiences: clayallsop, pleo)
- Level 1B: Total rename to TypeScript from the start
- "Just rename all .js files to .ts"?
- use the loosest, bare minimum settings to start with
- Level 2: Strict TypeScript
- use Microsoft's
dts-gen
to generate.d.ts
files for your untyped files. This SO answer has more on the topic. - use
declare
keyword for ambient declarations - see declaration merging to patch library declarations inline
- use Microsoft's
Misc tips/approaches successful companies have taken
@ts-ignore
on compiler errors for libraries with no typedefs- pick ESLint over TSLint (source: ESLint and TS Roadmap). You can convert TSlint to ESlint with this tool.
- New code must always be written in TypeScript. No exceptions. For existing code: If your task requires you to change JavaScript code, you need to rewrite it. (Source: Hootsuite)
Webpack tips
- webpack loader:
awesome-typescript-loader
vsts-loader
? (there is some disagreement in community about this - but read awesome's point of view) - Webpack config:
module.exports = {
resolve: {
- extensions: ['.js', '.jsx']
+ extensions: ['.ts', '.tsx', '.js', '.jsx']
},
// Source maps support ('inline-source-map' also works)
devtool: 'source-map',
// Add the loader for .ts files.
module: {
loaders: [{
- test: /\.jsx?$/,
- loader: 'babel-loader',
- exclude: [/node_modules/],
+ test: /\.(t|j)sx?$/,
+ loader: ['awesome-typescript-loader?module=es6'],
+ exclude: [/node_modules/]
+ }, {
+ test: /\.js$/,
+ loader: 'source-map-loader',
+ enforce: 'pre'
}]
}
};
Special note on ts-loader
and 3rd party libraries: https://twitter.com/acemarke/status/1091150384184229888
- https://github.com/Microsoft/TypeScript/wiki/JsDoc-support-in-JavaScript
- webpack's codebase uses JSDoc with linting by TS https://twitter.com/TheLarkInn/status/984479953927327744 (some crazy hack: https://twitter.com/thelarkinn/status/996475530944823296)
Problems to be aware of:
object
is converted toany
for some reason.- If you have an error in the jsdoc, you get no warning/error. TS just silently doesn't type annotate the function.
- casting can be verbose
(thanks Gil Tayar and Gleb Bahmutov for sharing above commentary)
the "Just Renaming" strategy
- OSX/Linux:
find src -name "*.js" -exec sh -c 'mv"$0" "${0%.js}.tsx"' {} \;
You can either load typescript files with webpack, or use the tsc
compiler to compile your TS files to JS side by side. The basic tsconfig.json
is:
{
"compilerOptions": {
"allowJs": true
}
}
Then you will want to enable it to check JS:
{
"compilerOptions": {
"allowJs": true,
"checkJs": true
}
}
If you have a large codebase and this throws too many errors at once, you can opt out problematic files with //@ts-nocheck
, or instead turn off checkJs
and add a //@ts-check
directive at the top of each regular JS file.
TypeScript should throw up some egregious errors here which should be easy to fix.
Once you are done, swallow the red pill by turning off implicit any
's:
{
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"noImplicitAny": true // or "strict": true
}
}
This will raise a bunch of type errors and you can start converting files to TS or (optionally) use JSDoc annotations in your JS.
A common practice here is using an ambient TODO type alias for any
so you can keep track of what you need to come back to:
type TODO_TYPEME = any;
export function myFunc(foo: TODO_TYPEME, bar: TODO_TYPEME): number {
// ...
}
Gradually add more strict
mode flags like noImplicitThis
, strictNullChecks
, and so on until you can eventually just run in full strict mode with no js files left:
{
"compilerOptions": {
"strict": true
}
}
More resources
- Adopting TypeScript at Scale - AirBnB's conversion story and strategy
- Migrating a
create-react-app
/react-scripts
app to TypeScript - don't usereact-scripts-ts
- Migrating an EJECTED CRA app to TS
- Lyft's JS to TS migration tool (includes PropTypes migration)
- Hootsuite
- Storybook's migration (PR)
- How we migrated a 200K+ LOC project to TypeScript and survived to tell the story - Coherent Labs - using
grunt-ts
, jQuery and Kendo UI
Old content that is possibly out of date
- Try flow2ts:
npx flow2ts
- doesn't work 100% but saves some time (see this and other tips from @braposo at TravelRepublic) - Incremental Migration to TypeScript on a Flowtype codebase at Entria
- MemSQL's Studio's migration - blogpost with many useful tips
- Retail-UI's Codemod: https://github.com/skbkontur/retail-ui/tree/master/packages/react-ui-codemodes/flow-to-ts
- Quick-n-dirty Flow to TS Codemod
- Ecobee's brief experience
- Migrating a 50K SLOC Flow + React Native app to TypeScript
- Number of production deploys doubled for Hootsuite
- Found accidental globals for Tiny
- Found incorrect function calls for Tiny
- Found rarely used, buggy code that was untested for Tiny
Our central finding is that both static type systems find an important percentage of public bugs: both Flow 0.30 and TypeScript 2.0 successfully detect 15%!
- Adopting TypeScript at Scale - AirBnB's conversion story and strategy
- Lyft
- Tiny - Talk from ForwardJS here
- Slack (podcast)
- Netflix adoption story
- Priceline
- Dropbox - Talk at React Loop
Open Source