Typescript is an exciting technology that has been around since 2012. It has been implemented by Microsoft, which constantly updates and improves the language and its tooling. Over the past few years, it has been used by many people and companies, making it one of the top trending languages on Github.
This documentation’s purpose is to expose a bit of why you should consider using it, and a lot of how you can use it. The main reason for this guide to exist, is that most guides around the web simply assume that you are already on the front seat of the hype train for Typescript. This guide assumes that you see Typescript like a father sees the new tattooed boyfriend of his daughter.
In the real world, Typescript is being used in a lot of large projects: VS Code is written in Typescript, Angular is written with and in Typescript, as well as Formik and RxJS, to name a few.
Before jumping to the good stuff, I guess it’s fair to add a small extract on why you would want to make your life harder. Typescript appears to be a burden to the neophyte eyes, nonetheless, I’m going to try my hardest to show how easy it can actually be to use it, and to enjoy it, without the hassle of suddenly having to write Java code.
Typescript reduces the number of unit tests you need to write
One of the first reasons I see is the insane gain of time when it comes to testing your code. If you wrote any tests at all before, you can count on a 10–20% decrease on how many you have to write. If you didn’t, then you gain those extra 20% at no cost!
This simple function already highlights the second problem I was going to expose: JS *does* have type already whether you like it or not. But for now, my point onward: in your unit test, you need to make sure your function throws when arguments are null, undefined, strings, etc… Another test is to make sure the function always returns a proper number and not (for example) an empty value.
Well, with Typescript, all those tests are catered for by Typescript itself. Not only you can explicitly assert that a and b are numbers, that the result is a number, but it also allows you to set a value as “nullable” or not.
Typescript helps you with regression
Back to the previously mentioned point. This line of code highlights which is, for me, one of the fundamental mis-wordings behind Typescript.
if(typeof a != 'number' || typeof b != 'number')
When working on a project with more than one developer, that becomes a problem. Not only issues can arise when updating dependencies, but also simply merging a PR can suddenly break an unrelated code simply because a function’s footprint slightly changes.
Typescript, when used smartly, can prevent all of that from happening with a minimal amount of work. We’ll get on to the “how” part later.
Typescript helps in discovering a project
Now onto the exciting bit: we’re going to set up Typescript in our project. See this guide like a peaceful and scenic train ride along the sea. Final Stop: Typescript-town. Along the way, while you admire the reflexion of the sunshine on the calm water, you’ll find a sequence of stops going from the minimal TS usage, to more advanced usages of it. Feel free to get off the train at the stop you are the most comfortable in.
Stop 1: At the beginning, was tsc, and tsc was with Typescript
Most basic usage
Let’s start our journey with some easy project setup. Make yourself a tea, so you can sip on it while NPM does the work for you. The simplest imaginable way to use Typescript is with `tsc`. Tsc stands for `TypeScript compiler` and is a simple tool included in Typescript itself, allowing you to compile any ts files into js.
npm install –global typescript
If you are familiar with NPM, I invite you to install Typescript locally to a project rather than globally, but proper NPM usage is out of the scope of this article.
Let’s now create our first ts file: test.ts (Yes, I’m big on naming things).
Simply compile your file with tsc, it will create a test.js file next to it which you can execute.
If you followed this guide properly all the way here (between you and me, you shouldn’t fail here already) then you should be able to admire your glorious palaver: “123”.
If, like me, you are using VSCode, you should have already been warned against this trickster code. If not, re-run tsc on it, and it should appear!
A word on config
Typescript comes with a whole lot of configs for you to customize your experience. To follow this article, I highly recommend you to use this generic, and very flexible config file. In the Appendix, I will give a bit more details on what it does and how to improve it for your taste.
If you get off the train here
If that’s all you wanted, you might want to take a look at a few additional pieces in order to help you streamline your tsc process.
The simplest way to do it, is to rely on tsconfig.json to get input/.
First change your tsconfig:
Use outDir and include to not have to manually compile every files
We essentially added two things: the “include” prop, which is “where your source files are” (here, src) and “outDir” which is “Where you want your output files to be” (here dist). Now, if you put test.ts in your src/ folder, alongside other ts files, simply running tsc without arguments will give you the same 1:1 structure as an output in the dist folder.
Next up, in order not to have to type “tsc” on every change, you can use “tsc — watch’ instead, which will update every time you save a file!
Use tsc –watch to automatically compile your changes
In the Appendix, I will explain how to make your pipeline fancier with webpack.
Stop 2: And Typescript said: “Let there be types”
Now, basic type checking for JS native features is cool. But obviously, we barely typed the surface, and there’s a lot more to it! Let’s take a look at how to bring in typing to your everyday coding without messing with your head. First, let’s start with some simple introduction:
Very easy, isn’t it? Simply add : to a variable to type its declaration. You can also type a function and its return value:
Another cool feature of TS is the notNullable check. This might seem already a bit strict for some people, so feel free to not enable it, but you might find it is actually pretty useful in the long run!
In your tsconfig :
When to type
Now the real question is, when do you need to use types and when do you not need them?
I’m going to open a short parenthesis here. A significant amount of people will try to make you set up your Typescript to be as strict as possible. Those people, comparing TS to Java or C, argue that because in C everything is typed, it’s natural for TS to type everything. Now, this is going to be a totally personal take on the subject: I strongly disagree.
Because of how dynamic and flexible JS is, typing everything can sometime end up in 3–4 lines declarations that can make your code ineligible.
So, after this long and boring parenthesis, let’s go to what I consider to be the 80/20 split of TS efficiency.
Type at least function parameters and return value
When you write code, your building blocks are function. Typing at least the input/output of each functions, means that on the long term, with only 20% of the work, you achieve 80% of typing protection. Every time someone updates a function, you expect it to be doing roughly the same thing. If the return or the parameters change, you will get a (nice) error, telling you to update your code to not introduce any regression.
The reason why typing sum is not as necessary is obvious since, when you write this function, you have the whole function in view, and catching an error is way easier than catching an error done in a completely different file! And if you ended up not doing the proper thing in the function itself, consider writing unit tests to make your function more robust instead of simply relying on more types.
If you are using React, forget about Proptypes, and use Typescript to explicitly type your props and states.
If you get off the train here
There it is! You have unleashed the power of Typescript on your codebase, and suddenly you feel how soothing it is to call a function written by someone else, and not have to worry about what you call it with, and whether or not it’s going to change/disappear. There is an additional aspect of Typescript that you might want to sit through though, writing a public library. When doing so, you probably want your typing to be a lot more explicit than they would be otherwise. Most libraries expose as well typing files available to you, making 3rd party integration a walk in the park. Sit tight, you’re almost there!
Stop 3: And Typescript said: “Let there be a vault between projects to separate projects from projects”
Let now see (and enjoy) how to install a 3rd party typing for a library. Let say that our project is using React (super original) and that we want typing for it.
Oh, by the way! Typescript just displayed an error saying I forgot to install React! Pretty cool, huh?
Let’s install React and its typing. Bring in your terminal and type:
npm install react @types/react
Now, run your usual tsc command and hop! Typescript will tell you to review your basics of using React *wink*.
How does it work?
When you executed the npm install command, npm created a new @typing folder in your node_modules. As you can see from the files in there (or from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts) the file is a .d.ts file, which is in Typescript called a “definition” file. It looks complex, but don’t worry, Typescript actually generated those for you!
Stop 4: And Typescript said: “I can’t think of another title”
I am not going to explain in here everything you can do with Typescript, if you are interested in those, you can check out some of the resources in the Appendix. I wanted to take some lines though, to show some of the more advanced typing acrobatics that you will definitely need to step up your T game.
Let’s start easy with interfaces. They are a simple way to type your JSON object. It’s good practice to start your interface names with a capital case I.
In most code base, please avoid having interface.ts files with hundreds of them. Be smart about your data model, and keep the interface close to those generating them (ex api/ folder).
Another useful trick is the union operator. Because sometimes, a function can take or return multiple kinds of value, you can use | to expose them all.
If your divergence becomes more complex, Typescript also support overloading
writeFile(id: string, data: string, callback: TCallback<void>);
writeFile(id: string, data: string, options: IWriteFileOptions | string, callback: TCallback<void>);
When you define an array, you might want to explicitly specify what you can put in them:
One of concepts that is carried over from typed language is type casting. Essentially, sometimes you will receive variables from outside sources, without having a specific type attached to it. It will then be your job to tell Typescript what type you want TS to consider this variable to be.
Custom lib types
In case you want to add some self-made documentation to a library that doesn’t have types (or maybe you want to force typing every libraries used as noted as possible in the Appendix), then you will want to be able to create custom types as such. Create a @types folder at the root of your project and a sub-folder with the name of the library to type. I’m going to choose React (original, I know).
Create a definition file:
And then simply add the “@types/**/*” folder in the “include” of your tsconfig.
If you made it all the way here, congratulations, you are a champion! If you just jumped to the conclusion, ignore that previous sentence. Typescript itself is essentially a new language and it will take you a bit of time to master the art of typing.
Don’t give up, and please take some time to take a look at the appendix, especially the additional resources which will be very useful to your new Typescript adventure!
As mentioned earlier, every tastes is in the nature when it comes to being constrained (no innuendo intended). If that’s your cup of tea, here are a few props you can look at to tighten your bonds.
This is probably the most impactful props you can set. It prevents you essentially from using any variable without an explicit type. The type doesn’t need to be set on the variable itself, it can come from the return type of a function, for example. But if you don’t have that indirect type at all, Typescript will raise an error.
You can silent the error by typing your variable to “any”.
If this is set to false, you won’t be able to use any library that is not fully typed anymore. You might have to do a lot of manual definition if you set that option and use outdated libraries.
In case you want to be a bit more flexible,
checkJs allows you to typecheck JS imported code (allowJs must be true).
When you set the return type of a function to be specific, with this option Typescript will ensure that you statically return a value on every branch of your function (ex: if / else / switch / …).
This needs to be a type, before being used.
All declared variables must be used.
All declared parameters of a function must be used.
Strict and sibblings
Strict will enable every — strict-* options. Those include null check, function types, etc… Check the documentation for more details.
React and JSX
Typescript supports JSX compilation out of the box. The only thing you need to do to use it is add a `
jsx` prop to your compiler options in tsconfig.json.
Set that prop to ‘react’ or ‘react-native’ depending on your need.
Babel and Webpack
You don’t have to use tsc to compile Typescript. If you are using Babel already, a package named babel-preset-typescript allows you to use Typescript within Babel itself.
In order to activate it, npm install it, then in your babel config, add :
If you are willing to use Webpack, consider using awesome-typescript-loader instead of the official typescript-loader. The former will have higher performance thanks to a better caching strategy.
Typescript documentation : https://www.typescriptlang.org/docs/home.html