TypeScript has become the go-to language for many developers, providing the benefits of static typing while maintaining the flexibility of JavaScript. However, as TypeScript continues to evolve, some practices that were once considered best may now be outdated or suboptimal. In this article, we’ll cover 10 bad TypeScript habits you should break in 2024 to write cleaner, more efficient, and maintainable code.
1. Not Using strict
Mode
The Problem:
Many developers disable TypeScript’s strict
mode to avoid dealing with stricter type checks.
Why It’s Bad:
When strict
mode is off, TypeScript becomes more lenient, reducing the effectiveness of type safety. This can lead to unexpected bugs and make refactoring more challenging in the future.
What to Do Instead:
Enable strict
mode in your tsconfig.json
. It will enforce better type checks and ensure that your code is more robust in the long run.
{
"compilerOptions": {
"strict": true
}
}
2. Relying on any
Too Much
The Problem:
The any
type is often used as a quick fix when developers don’t want to think about the correct type.
Why It’s Bad:
Using any
bypasses the entire purpose of TypeScript, making it essentially JavaScript again. This can lead to runtime errors, as TypeScript is no longer able to help catch mistakes during development.
What to Do Instead:
Use more specific types like unknown
, or better yet, define a proper type for your data. The unknown
type is safer than any
because it forces type-checking before using the value.
let data: unknown;
if (typeof data === "string") {
console.log(data.toUpperCase());
}
3. Using Type Assertions Carelessly
The Problem:
Type assertions (as
keyword) can be overused, especially when developers are unsure about types and want to silence TypeScript errors.
Why It’s Bad:
Type assertions can lead to unsafe code because they tell TypeScript to treat a value as a specific type, even if it might not be. This can result in runtime issues if the value isn’t what you expect.
What to Do Instead:
Limit type assertions. Instead, use type guards, which allow you to safely check and infer types before using them.
function isString(value: unknown): value is string {
return typeof value === 'string';
}
if (isString(data)) {
console.log(data.toUpperCase());
}
4. Neglecting Union and Intersection Types
The Problem:
Some developers avoid using union (|
) and intersection (&
) types, even when they would make the code more expressive and precise.
Why It’s Bad:
Without union and intersection types, your code can become overly verbose, and you might miss out on TypeScript’s ability to describe complex data structures more concisely.
What to Do Instead:
Leverage union and intersection types to create more flexible and reusable type definitions.
type Admin = { isAdmin: true; privileges: string[] };
type User = { isAdmin: false; email: string };
type Person = Admin | User;
function logUser(person: Person) {
if (person.isAdmin) {
console.log(person.privileges);
} else {
console.log(person.email);
}
}
5. Using Non-Specific Return Types
The Problem:
Functions often have return types of any
, object
, or other non-specific types, leaving the consumer of the function to figure out what to expect.
Why It’s Bad:
Non-specific return types make your code less predictable and harder to debug. You lose the benefit of TypeScript’s static type checking, making your code more error-prone.
What to Do Instead:
Always specify the exact return type of a function. If the function returns multiple types, use union types to describe them.
function fetchData(): Promise<{ id: number; name: string }> {
return fetch("/data").then(response => response.json());
}
6. Ignoring null
and undefined
The Problem:
Some developers ignore the presence of null
and undefined
values in their code, leading to unexpected errors.
Why It’s Bad:
JavaScript allows variables to be null
or undefined
, and TypeScript provides tools to handle these values explicitly. Ignoring them can lead to runtime errors when accessing properties or calling methods on null
or undefined
.
What to Do Instead:
Use optional chaining and the nullish coalescing operator to safely handle null
and undefined
values.
const name = user?.profile?.name ?? "Guest";
7. Overusing Enums
The Problem:
Enums
are often overused for simple constant values, when other types like const
or literal unions could suffice.
Why It’s Bad:
Enums can add unnecessary complexity, especially when simpler alternatives exist. In some cases, they can even introduce issues related to mutability.
What to Do Instead:
Use literal types or const
objects for simple constant values.
type Role = "Admin" | "User" | "Guest";
let userRole: Role = "Admin";
8. Not Utilizing readonly
The Problem:
Failing to use the readonly
keyword leads to mutable data structures, which can cause bugs and unintended side effects.
Why It’s Bad:
Mutability can lead to accidental modifications of objects or arrays, making it harder to trace bugs.
What to Do Instead:
Use readonly
to enforce immutability where appropriate.
const data: readonly number[] = [1, 2, 3];
9. Neglecting Custom Type Guards
The Problem:
Many developers rely on implicit checks rather than using custom type guards to ensure type safety.
Why It’s Bad:
Without explicit type guards, you risk missing certain types during runtime, leading to potential errors.
What to Do Instead:
Implement custom type guards to explicitly check types and make your code more reliable.
function isUser(user: any): user is User {
return typeof user.email === "string";
}
10. Not Taking Advantage of unknown
Type
The Problem:
Developers often default to using any
for variables when the type is initially unknown.
Why It’s Bad:
any
disables type checking, which defeats the purpose of using TypeScript.
What to Do Instead:
Use the unknown
type for variables when you’re not sure about the type initially, and narrow the type as needed.
let input: unknown;
if (typeof input === "string") {
console.log(input.toUpperCase());
}
Conclusion
Breaking these bad TypeScript habits in 2024 will help you write more maintainable, performant, and error-free code. By embracing stricter typing, avoiding shortcuts like any
, and fully leveraging TypeScript’s advanced features, you can significantly improve your code quality and become a more effective developer.
That's all for today.
And also, share your favourite web dev resources to help the beginners here!
Connect with me:@ LinkedIn and checkout my Portfolio.
Explore my YouTube Channel! If you find it useful.
Please give my GitHub Projects a star ⭐️
Thanks for 32017! 🤗
This is a submission for the 2024 Hacktoberfest Writing challenge: Contributor Experience