5 Essential Tips For TypeScript Developers

5 Essential Tips For TypeScript Developers

Developers have been drawn to TypeScript because of its ability to provide strong typing and improved tooling to JavaScript projects. If you're a professional developer looking to get the most out of TypeScript, there are several important tips to keep in mind. In this article, we will explore the most important TypeScript development tips that will boost your skills and help you code more efficiently.

1. Get to know TypeScript's type system

A key advantage of TypeScript is its robust static type system. In order to use TypeScript effectively, it is crucial to have a solid understanding of how types work and how to use them. Make yourself familiar with TypeScript's built-in types, such as strings, numbers, booleans, and objects, as well as more advanced features such as generics and unions. When types are used correctly, not only will potential bugs be caught early, but also readability and maintainability will be improved.

// Example: Using types in TypeScript
function greeting(name: string): string {
   return `Hello I am, ${name}!`;
}
const message: string = greeting("Muthu");
console.log(message); // Output: Hello I am, Muthu!

2. Enhance code organization with enums

In TypeScript, Enums enable you to create named constants. An enum defines related values in the form of numbers or strings. As they allow grouping related values, they are a very useful way to organize our code and ensure type safety.

When defining an enum, use the enum keyword followed by its name, then its named constant in curly braces, as follows:

enum Car { 
      Honda, 
      BMW, 
      Audi 
} // usage let car = Car.BMW;

As a default, the first enum key is set to 0, unless it is defined otherwise (it can also be defined as a string), then each member increments by one. Under the hood, the example above looks like this:

enum Car { 
    Honda = 0, 
    BMW = 1, 
    Audi = 2
}

If you decide on a numeric value for the first member of the enumeration, then each subsequent member is incremented by 1 from that value:

enum Car { 
    Honda = 1, 
    BMW, 
    Audi 
}

In the above illustration, Honda = 1, BMW = 2, and Audi = 3.

In situations where you have a finite number of constant values, like directions, enums can prove invaluable help. Working with those values can be more structured and type-safe using an enum

enum Direction {
    Up = 1,
    Down,
    Left,
    Right,
}

3. Whenever possible, use tuples over arrays

Object types are commonly used to represent structured data, but sometimes you may prefer a simpler representation and use simple arrays. For example we can define our Rectangle as follows:

type Rectangle = (string | number)[]; 
const rectangle: Rectangle = ['rectangle', 2.0];

In a situation like this, the typing is unnecessarily loose, and it is easy to make a mistake if you create something like ['rectangle', '2.0']. By using Tuple instead, we can make it stricter:

type Rectangle = [string, number];
const rectangle: Rectangle = ['rectangle', '2.0'];

React's useState is a good example of Tuple usage.

const [name, setName] = useState('');

In addition to being compact, it is also type-safe.

4. Take advantage of advanced type features

You can greatly improve your development workflow with TypeScript's advanced type features. Use features such as type inference, type guards, conditional types, mapped types, and intersection types. By using these features, you can write concise, expressive code while maintaining strong type safety. Additionally, you can leverage type definition files (d.ts) provided by popular libraries and frameworks for better development.

// Example: Using conditional types in TypeScript
type CheckFunction<T> = T extends string ? boolean : number;

const resultString: CheckFunction<"Hello world"> = true;
const resultNumber: CheckFunction<50> = 50;
console.log(resultString); // Output: true
console.log(resultNumber); // Output: 50

5. Make use of utility types

In general, utility types will help you simplify your life as a software developer, reduce your code base, reuse existing types, and make your type system more “stiff ”.

As an example, here I can use Omit utility type instead of creating another interface, to remove the id property that I do not need in the createUser function:

// bad approach
interface CandidateData {
    emailId: string;
    hashPassword: string;
    createdDate: string;
}
interface Candidate extends CandidateData {
      id: string;
}
function createCandidate(candidateData: CandidateData) { ... }

// good approach
interface Candidate {
    emailId: string;
    hashPassword: string;
    createdDate: string;
}
function createCandidate(candidateData: Omit<Candidate, 'id'>) { ... }

If I don't need to use id, I can omit it instead of using inheritance. This version is much more readable and less complex, since CandidateData really doesn't inherit from Candidate.

Conclusion

TypeScript is an effective tool for writing scalable and maintainable code. Incorporating enums, type annotations, union types, and type predicates will greatly enhance the type safety and overall flexibility of your code. Annotations assist in catching errors early and provide better documentation, while enums and unions simplify code and make it more self-explanatory. By using type predicates and generics, you can create functions and classes that are reusable and adaptable.

Did you find this article valuable?

Support Muthu Annamalai Venkatachalam by becoming a sponsor. Any amount is appreciated!