We use Typescript in multiple parts of our stack, Angular, NestJS and general bundles compiled by Webpack. But there are so many ways to do things and, over time, I've learnt a lot of tweaks that allow me to create cleaner and more maintainable code. So this article outlines some of the main points that I've learnt throughout my Typescript journey, I hope they help you as much as they helped me :)
1) TSConfig paths
Sometimes there's a class or module that you use throughout your code. The imports can get quite messy if you have deeply nested components or files. Here's where modifying the
paths key in the
tsconfig.json file comes in handy.
You can create a path to a specific file or folder. I'll outline how to do both and then show you how to use them in code. Here's an example of a
tsconfig.json file with a few paths defined.
@config path assumes there is a barrel file (This is described later in the article but assume an
index.ts exists). In this case, you can import any of the objects, types, etc that the barrel file exports.
@logger points directly to a file called
logger.service.ts and this makes it really easy to import my
LoggerService anywhere in the project.
@modules refers to a folder and allows you to simplify your imports. The example below should show why this is cool.
*** There is a downside ***
As with most awesome things, it's not really a one-size-fits-all solution. When you use paths and compile to
.js files are unable to resolve the paths. To get this working again, you have to bootstrap a file that loads the paths. Check this Github Issue for instructions on how to do it.
It's not too difficult to get it working so I think the pros far outweigh the cons.
2) The spread operator
Sometimes, we want to combine multiple objects or copy one that already exists. The spread operator really makes merging objects a lot easier.
What's awesome about the spread operator is that the order matters in terms of which key takes priority. The keys that appear at the end overwrite the ones at the start.
There are plenty of places where this is useful. A few places we use it include:
ngrxto overwrite specific keys in the store while leaving the value of the rest.
- To create a new object (with a new memory address) with the same values as the old one.
- In parameters in functions, this is super cool but I'll leave you to investigate this more. Maybe start here.
3) Configs using barrel files
Configs can be quite difficult to get right. If you are reading from a
.env file, you need to make sure that runs first before accessing the values. There's also the aspect of keeping configs as dynamic as possible, but when you use string paths to get the config, the IDE will not autocomplete for you. I found a pretty cool way to create a config but it's a bit too long to write out in this article, so check out my other article here.
4) Maps can use anything as a key
Okay this functionality is super awesome! Did you know that the
Map type can take anything as a key? It seems like it's not useful but we've been able to build some really cool decorators in Typescript because of it. An example is that you can use a class type as a key and attach metadata to that.
5) Object key names
You don't have to specify the key name in an object (when you're creating it) if the variable name has the same name. It's quite a small thing but it makes your code far more readable.
6) Partial types
Sometimes we don't need to pass in a full model but we do want to pass in some of it. In that case, we can use the
Partial type to make a function accept an object that has a subset of keys.
Now this would allow us to send in an object that has some of the keys but not all of them. However, this doesn't force certain keys to be there. So you can use other types to use some keys and not others. Check type-fest on GitHub for some useful type examples.
These are a few things that I've learnt over the years of working with Typescript. I'll keep this updated as and when I find more cool stuff.
Hope this helps :)!