10 TypeScript Hints
for Developers Coming from Other Languages
Transitioning to TypeScript can be a significant shift for developers accustomed to other programming languages. TypeScript, a superset of JavaScript, offers static typing and other powerful features that can enhance code quality and readability. Here are ten valuable hints to help developers coming from other languages get up to speed with TypeScript's unique capabilities.
1. Structural Typing
That may be not obvious to people used to classes in other languages with strict type checking. In such languages you cannot interchangeably use instances of two different classes, even if these classes have the same structure.
Typescript on the other hand embraces the “duck typing” or “structural typing” paradigm. This means that if two objects have the same shape, Typescript considers them to be of the same type. This approach allows for greater flexibility in code and makes it easier to work with types that share the same structure.
For example we can use objects without explicitly defined types.
Or we can interchangeably use values of two types having the same structure.
2. Use types
instead of interfaces
Both type
and interface
can be used to define shapes of objects or function signatures and most of the time they can be used interchangeably.
The most important difference is that interfaces are not set in stone and anybody can extend an interface. You can even define interface twice in the same file and the result would be merge.
Benefits of types over interface:
Most likely you will have to use type
syntax in your project anyways to transform types.
For example omit some values.
That is not possible to do with interfaces. If you use types everywhere you will have more consistent syntax across your project.
Types are easier to reason about
Types are defined only once and you cannot change them, meaning you don’t have to worry that somewhere may be some additional type declaration which adds something to it.
Why do we need interfaces then?
You are working on a public library or framework
In such case if you use interfaces, that will allow developers using library to extend it. For example they may create a plugin to your framework and provide additional fields to your types.
Interfaces integrate better with classes
You can make a class implement an interface as in many other languages.
But from my experience in most of the modern libraries you don’t use classes at all.
3. Learn Utility Types
Utility types in TypeScript provide powerful ways to transform existing types into new variants, which can be incredibly useful for creating type-safe code without redundancy. Some commonly used utility types include Partial<T>
, Readonly<T>
, Record<K,T>
, and Pick<T,K>
. Familiarizing yourself with these can significantly enhance your ability to manipulate and use types. For a comprehensive list and documentation, refer to the TypeScript official documentation on Utility Types at https://www.typescriptlang.org/docs/handbook/utility-types.html
And few examples on what you can do with them
4. Use Libraries to Manipulate Objects
Sometimes you need to convert objects of one type to another, there are already few libraries which can make your life easier in such case.
For example they have omit, pick methods which relate quite nicely to Omit and Pick utility types.
For example
5. You Don’t Need to Put Types Everywhere
One common misconception about TypeScript is that developers need to annotate every variable with a type. TypeScript’s type inference is powerful and can often deduce the type of a variable from its usage. Use explicit types when necessary for clarity or to enforce constraints, but also leverage type inference to keep your code clean and readable.
For example
I would advise though to always add explicit type declarations to public modules functions which are not trivial.
In such case explicit type definition increases readability, since you don’t have to interpret the code to understand what the function does.
6. Literal, Union, and Algebraic Data Types
Literal types allow you to specify exact values that a variable can hold, while union types enable you to say a variable can be one of several types. Combining these two features can create powerful type assertions that enhance code safety and readability, such as defining a variable that can only hold specific string or number values.
An algebraic data type is a kind of composite type, formed by combining other types. It is probably easier to show with an example.
Lets imagine we have a function which returns either successful result or an error. How can we do that?
7. Type Guards
Sometimes the way to check type is not straightforward and you implement a helper function to do the check.
But then your realize this check doesn’t help you much because you still have to cast pet to Fish to use it.
To fix that you need to use type predicates (or type guards). Lets rewrite our helper function
Notice that instead of boolean
we used pet is Fish
for the return type. That way if we return truthy value from the function, the TypeScript will know that our pet is a fish.
Now there is one particular use case where I find this helpful.
For example, lets say we have users, some of them have middle names, and we need to get the list of all middle names and uppercase it
Lets define a function with a type predicate to check for defined values
8. How to Transform Nested Fields types
Lets imagine we have an API which returns a list of object which have another objects inside them. For example
But we don’t want to use dates as string, we want native JavaScript Dates.
So we create a function which transforms users and deserializes dates
But how can we create type for such user without copy pasting all the fields?
Lets use some utility types
9. Add intermediate type to narrow down type errors
Lets try the following example
The error message is quite long, how can we narrow it down?
You can add as SomeType
to the intermediate results.
Lets try
Of course you don’t need to put as
everywhere, but that technique may help you identify the error.
10. Prettify type
Kudos to Matt Pocock who introduced this super helpful type, and to https://www.totaltypescript.com who made a great explanation of it here
The Prettify
helper is a utility type that takes an object type and makes the hover overlay more readable.
It’s also not globally available in TypeScript — you’ll need to define it yourself using the code above.
Let’s imagine that you’ve got a type with multiple intersections:
If you hover over Intersected
, you'll see the following:
This is a little ugly. But we can wrap it in Prettify
to make it more readable:
And then on hover you will see much cleaner type information
I hope you’ll find these hints helpful and they will improve your understanding of TypeScript and make your life easier. Of course there is much more than that. Please let me know in the comments if you would like to see more tips & tricks for TypeScript.