It shouldn’t come as a shock that TypeScript is getting extra traction amongst builders by the day. Help for it has grown significantly, in addition to the group and variety of tasks adopting this expertise.
It wasn’t all the time like that, although. Internet builders have been burned earlier than by sizzling applied sciences that disappeared, and it’s solely truthful that some in the neighborhood are extra skeptical about large adjustments. In reality, the Lindy impact proposes that daily a bit of expertise continues to outlive, the longer it’s anticipated to exist.
The purpose of this text is to not persuade you emigrate to TypeScript; I assume that if you’re right here, you might have already been offered on the advantages of static typing in a dynamic language like JavaScript. Nonetheless, if you’re like me, you most likely have been delaying the migration, frightened of the quantity of labor wanted to set it in movement.
Nicely, worry no extra! I’ve accomplished the heavy lifting for you. On this article, you’ll learn to undertake TypeScript incrementally, so you’ll be able to have a clean transition and a very good evening of sleep after work.
Contents
Why incrementally?
Why do now we have “incrementally” within the title of this text? Isn’t that simply delaying the inevitable? Why not carry out a full migration directly?
These are legitimate factors, and in some circumstances, they will even be essentially the most advisable. Nonetheless, I’m assuming you might have a considerably giant venture, large enough that utilizing a codemod gained’t work (or would require an excessive amount of workaround).
Or possibly you’re employed on a particular a part of an app in a bigger staff and wish to run a pilot earlier than doing the massive change.
In all circumstances, there are legitimate eventualities the place one would take the cautionary street first. And regardless that you will see that a bunch of codemods or migration strategies that declare to be seamless, the truth is that in case your venture has some complexity, it may not be as straightforward as they preach.
Extra nice articles from LogRocket:
Nonetheless, to supply a counterpoint, the oldsters at Stripe appear to disagree with me. They simply not too long ago printed a piece claiming to have migrated thousands and thousands of traces of code to TypeScript. If you’re feeling adventurous, it’s price checking it out!
The right way to arrange TypeScript in an present Gatsby app
Alright, for immediately’s experiment we’ll assume you have already got a Gatsby app and wish to carry out a gradual migration.
Keep in mind that if you’re creating a brand new venture immediately, Gatsby already helps TypeScript as the primary language from the start. Sadly, that’s not the case for many tasks that have been bootstrapped in older variations of Gatsby, so we’re going to take a distinct route.
The Gatsby docs already current a good information on the right way to migrate. Nonetheless, there are a couple of tweaks that we have to do so as to get it up and operating easily.
Change your .js recordsdata to .tsx
The better half is to vary all parts you wish to migrate to .tsx, or create new ones on this format. No work is required on Gatsby’s aspect for this to work! That’s fairly neat.
Set up dependencies
There are, nevertheless, some libraries to be put in. Be sure to add them to your devDependencies
:
$ npm i –save-dev @varieties/node @varieties/react @varieties/react-dom typescript
Generate .tsconfig
TypeScript has a config file known as .tsconfig
, which is vastly customizable and can fluctuate from venture to venture. Nonetheless, there are some particular adjustments we have to make so as to enable TypeScript and JavaScript to coexist in concord, as this can be a requirement for everybody to undertake TS steadily.
An instance of a working .tsconfig
is as follows. Be certain so as to add it to the basis folder of your venture:
{ "compilerOptions": { "goal": "es2016", "jsx": "react", "module": "commonjs", "allowJs": true, "outDir": "./dist", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true }, "exclude": ["node_modules", "public", ".cache"] }
You can too test an instance on this public repo in GitHub.
Among the wanted configs are as follows:
- Add
"jsx": "react"
to ensure the compiler is aware of we’re in a React venture - Set
allowJs: true
; as soon as JavaScript and TypeScript must coexist, this flag must be turned on - Add
outDir: "./dist"
, which makes VS Code completely satisfied and prevents undesirable errors
Declaring globals
Should you received this far, you have already got most of your setup working. Nonetheless, there are nonetheless some tough edges.
The obvious is about CSS modules; Gatsby works with CSS modules by default and we have to let TypeScript be completely satisfied about it. Should you use SVGs as parts as described right here, this will even be helpful.
On the src
folder of your venture, create a file known as globals.d.ts
and add the next:
declare module "*.module.css"; declare module "*.module.scss"; declare module "*.svg" { const content material: string; export default content material; }
This can ensure that each CSS and SVG are handled and dealt with as modules.
Once more, you’ll be able to test a working instance in GitHub.
If you’re utilizing ESLint, it could complain about .d.ts recordsdata. On this case, you’ll be able to disable the linter in such extensions.
Typing utilizing prop varieties
One of many most important benefits of TypeScript is to permit static typing in JavaScript. When growing with React, that is a lot welcomed, as a result of it makes it more durable for us so as to add non-existing props and even move the incorrect variable.
Earlier than TypeScript was a factor, the React staff popularized typechecking with prop varieties.
Prop varieties have been an middleman step between no validation and strict typing. With prop varieties, builders might listing all props in a given element, their corresponding sort, and whether or not they’re optionally available or necessary.
For instance, suppose now we have a element that receives a prop known as magicNumber
, which in fact ought to have the sort quantity:
import PropTypes from 'prop-types' const MyComponent = ({ magicNumber }) => { … } MyComponent.propTypes = { magicNumber: PropTypes.quantity.isRequired }
Suppose then that we render MyComponent
however overlook to move magicNumber
as prop, or move a string as an alternative. We’d see a warning like this within the console, when in dev mode:
Nonetheless, there could be no static validation, and it’s straightforward to miss this type of error in larger parts or bigger tasks. Additionally, we are able to add a prop however overlook to set its sort (there are some linters that provide help to with that although).
Utilizing static typing, you’ll be able to deprecate prop varieties in favor of normal TypeScript varieties:
sort Props = { magicNumber: quantity } const MyComponent = ({ magicNumber }: Props) => { … }
Now, you probably have a .tsx element that renders MyComponent
, passing a prop with the incorrect sort will elevate an error at construct time:
And that’s it! Safer, however much less verbose, and comes with all typing advantages. All in all, prop varieties work however are much less highly effective than a strong typing technique like TypeScript. If you wish to get deeper on this topic, I like to recommend you learn our preview article on the topic: Evaluating TypeScript and PropTypes in React purposes.
If you’re satisfied that static typing is superior to prop varieties, you must also know that there’s a caveat when ditching prop varieties in a venture that may be a hybrid of TypeScript and JavaScript.
Suppose that now we have a WithTypeScript.tsx
element that renders the TypeScript model of MyComponent
. If we attempt to move magicNumber="Hi there World"
that is going to boost an error as soon as there’s a sort mismatch, as seen above.
Nonetheless, if WithTypeScript.tsx
receives magicNumber
from a mother or father element written in pure JavaScript and passes it alongside to MyComponent.tsx
, there is no such thing as a solution to validate if the variable is certainly a quantity. As soon as the mother or father element has no typing, no static error might be raised. And since there are not any prop varieties in MyComponent.tsx
, no runtime error might be raised. As such, this kind mismatch gained’t be raised anyplace.
Word how IndexPage.js
calls a TypeScript element WithTypeScript.tsx
with a incorrect prop sort. No warning is seen both within the editor or within the browser console.
Keep in mind that this solely occurs when .js and .tsx parts are speaking, which is able to inevitably occur if you’re steadily adopting TypeScript. Thankfully, there’s an answer for it: we are able to have one of the best of each worlds by inferring varieties from prop varieties in TypeScript parts. This manner, we retain the prop varieties, however routinely convert them into varieties utilizing the operate InferProps
from the prop-types library.
This could be MyComponent.tsx
combining varieties and prop varieties:
import React from "react"; import PropTypes, { InferProps } from "prop-types"; const Props = { magicNumber: PropTypes.quantity.isRequired, }; sort MyComponentTypes = InferProps<typeof Props>; const MyComponent = ({ magicNumber }: MyComponentTypes) => { … }; MyComponent.propTypes = Props; export default MyComponent;
A full instance could be seen right here.
The above answer will elevate a static error at construct time if there’s a sort mismatch, but in addition elevate a runtime error within the browser console if the incorrect sort is handed from a .js to a .ts element alongside the way in which. The disadvantage is that your code turns into extra verbose.
Nonetheless, if newer parts solely talk with different .ts recordsdata, then it must be secure to ditch prop varieties. Ultimately, when the migration is full, you’ll be able to fully take away them.
Conclusion
TypeScript is an distinctive tooling, however some builders chorus from adopting it in an present codebase. This text aimed to elucidate how you are able to do it safely in your venture, proper now, with out main adjustments.
Whereas Gatsby specifically helps .tsx recordsdata out of the field, you want some workarounds to make your compiler completely satisfied contemplating typical approaches current in Gatsby codebases. Declaring globals for CSS Modules and SVGs are widespread ache factors.
Lastly, by having JavaScript speaking with TypeScript, we are able to’t assure that some typing errors gained’t be opaque. Due to that, we are able to leverage the prop-types library and infer the kinds, getting one of the best of each worlds till we’re secure to deprecate.
All code and examples current on this article could be present in this repo in GitHub. Give it a strive!
Writing numerous TypeScript? Watch the recording of our latest TypeScript meetup to study writing extra readable code.
TypeScript brings sort security to JavaScript. There generally is a rigidity between sort security and readable code. Watch the recording for a deep dive on some new options of TypeScript 4.4.