5 Essential Flags to Enable on Your TypeScript Code
Tags: typescript, javascript, programming
Published: 2024-07-10 21:53:05

## Introduction
TypeScript is a powerful tool that brings static typing to JavaScript, providing a robust foundation for building scalable and maintainable applications. To maximize the benefits of TypeScript, it's crucial to enable certain compiler options flags that enhance type safety and code quality. In this article, we'll explore five essential flags you should enable in your TypeScript projects and how they can help you write better code.

## Initial Setup
In this article, we will cover the TypeScript flags: `noImplicitAny`, `strictNullChecks`, `strictPropertyInitialization`, `noImplicitReturns`, and `noUnusedParameters`. To enable each flag, you need to update your `tsconfig.json` file, setting these flags to true as shown in the example below:

```json
{
  "compilerOptions": {
    // ...other configurations
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictPropertyInitialization": true,
    "noImplicitReturns": true,
    "noUnusedParameters": true
  }
}
```

## 1. Avoid using 'any' type
- **Flag:** `noImplicitAny`
- **Description:** The `noImplicitAny` flag ensures that you explicitly declare types instead of defaulting to the `any` type. This enhances type safety by preventing untyped variables from creeping into your codebase.
- **Pro Tip:** Instead of using `any`, leverage the `unknown` type. To check if a variable is of the type you want, use type guards. If you're unfamiliar with type guards, check out this article: [Elevate Your TypeScript Skills with Type Guards](https://dev.to/geraldhamiltonwicks/elevate-your-typescript-skills-with-type-guards-ts-36k7). This practice enforces better type checks and reduces runtime errors.

When you enable `noImplicitAny`, TypeScript will issue an error whenever it would have inferred `any`:

```typescript
function fn(s) {
  // Type Error: Parameter 's' implicitly has an 'any' type.
  console.log(s.subtr(3));
}
```

## 2. Enable strict null checks
- **Flag:** `strictNullChecks`
- **Description:** Enabling `strictNullChecks` ensures that `null` and `undefined` are only assignable to their respective types. This prevents common pitfalls related to null values and improves code reliability.
- **Pro Tip:** Use optional chaining (`?.`) and nullish coalescing (`??`) operators to handle `null` and `undefined` values gracefully.

Setting `strictNullChecks` to true will raise an error if you try to use a variable that could be `null` or `undefined` without a proper check:

```typescript
declare const loggedInUsername: string;

const users = [
  { name: "Oby", age: 12 },
  { name: "Heera", age: 32 },
];

const loggedInUser = users.find((u) => u.name === loggedInUsername);
// Type Error: 'loggedInUser' is possibly 'undefined'.
console.log(loggedInUser.age);
```

## 3. Enforce strict property initialization
- **Flag:** `strictPropertyInitialization`
- **Description:** The `strictPropertyInitialization` flag ensures that all class properties are initialized either in the constructor or with a default value. This helps catch uninitialized properties early in the development process.
- **Pro Tip:** Use definite assignment assertions (`!`) when you're sure a property will be initialized by the time it's accessed.

When set to true, TypeScript will raise an error when a class property is declared but not set in the constructor:

```typescript
class UserAccount {
  name: string;
  accountType = "user";
  // Type Error: Property 'email' has no initializer and is not definitely assigned in the constructor.
  email: string;

  constructor(name: string) {
    this.name = name;
    // Note that this.email is not set
  }
}
```

## 4. Enable noImplicitReturns
- **Flag:** `noImplicitReturns`
- **Description:** The `noImplicitReturns` flag ensures that all code paths in a function return a value. This helps catch logical errors where a function might accidentally return `undefined` or no value at all.
- **Pro Tip:** Review your functions to ensure they have consistent return statements, providing a clear and predictable flow of data.

When enabled, TypeScript will check all code paths in a function to ensure they return a value:

```typescript
// Type Error: Function lacks ending return statement and return type does not include 'undefined'.
function lookupHeadphonesManufacturer(color: "blue" | "black"): string {
  if (color === "blue") {
    return "beats";
  } else {
    ("bose");
  }
}
```

## 5. Enable noUnusedLocals and noUnusedParameters
- **Flags:** `noUnusedLocals`, `noUnusedParameters`
- **Description:** These flags help you maintain a clean codebase by reporting unused local variables and parameters. This reduces clutter and makes the code more readable.
- **Pro Tip:** Regularly review and refactor your code to remove unused variables and parameters, keeping your codebase clean and efficient.

These flags will report errors for unused variables and parameters, helping you keep your code tidy:

```typescript
// Type Error: 'modelID' is declared but its value is never read.
const createDefaultKeyboard = (modelID: number) => {
  const defaultModelID = 23;
  return { type: "keyboard", modelID: defaultModelID };
};
```

## Conclusion
Enabling these essential TypeScript flags not only enhances type safety but also promotes best practices and code maintainability. By leveraging TypeScript's powerful type system and compiler options, you can write more robust and reliable code, ultimately leading to a smoother development experience.

By incorporating these flags and best practices into your TypeScript projects, you'll be well on your way to writing cleaner, safer, and more maintainable code. And you, what are the flags that you use in your TypeScript code?