The 5 Common Mistakes Beginners Make in TypeScript (and How to Avoid Them)
Mike Codeur
TypeScript is a powerful tool that makes JavaScript development safer and more maintainable through its static typing system. However, beginners often fall into pitfalls that can complicate their code or negate the benefits of TypeScript. In this article, we'll explore 5 common mistakes and how to avoid them with concrete examples.
1. Overusing any
The Problem:
Overusing any
bypasses TypeScript's static typing, essentially reverting to classic JavaScript. This can hide errors and make your code harder to maintain.
Example of Mistake:
function addition(a: any, b: any) {
return a + b; // May produce unexpected behavior
}
console.log(addition("1", 2)); // Output: "12"
The Solution:
Use explicit types or generics when needed.
Corrected Example:
function addition(a: number, b: number): number {
return a + b;
}
console.log(addition(1, 2)); // Output: 3
2. Incorrectly Typing Objects
The Problem:
Many beginners fail to properly define object structures or use overly permissive typing.
Example of Mistake:
const user: object = { name: "Alice", age: 25 };
// Error if trying user.name, as TypeScript doesn't recognize object properties.
The Solution:
Define interfaces or types to precisely describe your objects.
Corrected Example:
interface User {
name: string;
age: number;
}
const user: User = { name: "Alice", age: 25 };
console.log(user.name); // Output: "Alice"
3. Overcomplicating Types
The Problem:
Combining too many types or adding unnecessary constraints can make your code unreadable and harder to maintain.
Example of Mistake:
type Account = { id: number; email: string } | { id: number; username: string };
const user: Account = { id: 1, email: "[email protected]", username: "test" };
// Potential error: the type doesn't know which property to use.
The Solution:
Simplify complex types or use discriminants to clarify your intentions.
Corrected Example with a Discriminant:
type EmailAccount = { type: "email"; id: number; email: string };
type UsernameAccount = { type: "username"; id: number; username: string };
type Account = EmailAccount | UsernameAccount;
const user: Account = { type: "email", id: 1, email: "[email protected]" };
4. Ignoring TypeScript Configuration Options
The Problem:
Many beginners skip configuring tsconfig.json
properly, which can hide potential errors.
Common Example:
A project without strict options enabled:
{
"compilerOptions": {
"strict": false}
}
This allows imprecise behavior, such as not checking if properties exist.
The Solution:
Enable strict options to fully leverage TypeScript.
Recommended Configuration:
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true}
}
5. Confusing Types and Interfaces
The Problem:
Beginners often struggle to choose between type
and interface
. While similar, they have specific use cases.
Example of Mistake:
type User = { name: string };
type Admin = User & { permissions: string[] };
interface User { name: string; }
interface Admin extends User { permissions: string[]; }
// Mixing these approaches unnecessarily.
The Solution:
Use interface
for objects or when inheritance is needed. Use type
for complex combinations or unions.
Corrected Example:
interface User {
name: string;
}
interface Admin extends User {
permissions: string[];
}
const admin: Admin = { name: "Alice", permissions: ["read", "write"] };
Bonus: Setting Up a React/Next.js Project with TypeScript
Step 1: Create a Project
- For React:
npx create-react-app my-project --template typescript
- For Next.js:
npx create-next-app@latest my-project --typescript
Step 2: Check tsconfig.json
Next.js automatically generates a tsconfig.json
file with suitable options. Ensure the following settings are enabled:
{
"compilerOptions": {
"strict": true,
"baseUrl": ".",
"paths": {
"@/components/*": ["components/*"],
"@/utils/*": ["utils/*"]
}
}
}
Step 3: Add Global Types
To avoid repeating the same types, create a types/global.d.ts
file:
declare module "*.css";
declare module "*.png";
Step 4: Use Typed Props
Typing for a React component:
interface Props {
title: string;
age?: number; // Optional
}
const MyComponent: React.FC<Props> = ({ title, age }) => (
<div>
<h1>{title}</h1>
{age && <p>Age: {age}</p>}
</div>
);
Conclusion
TypeScript is a fantastic tool, but like any tool, it requires some learning to avoid common mistakes. By following these tips, you can steer clear of frequent pitfalls and fully harness the power of TypeScript. Ready to write safer code?