Day 38: Assertions
Tags: javascript, typescript, 100daysofcode, day38
Published: 2023-09-01 14:15:00



### What is a Type Assertion?

A type assertion tells to TypeScript, "Trust me, I know the type better than you do." It's like a developer's secret handshake, allowing you to override TypeScript's type inference and specify the type of a variable. They come in two flavors: the `angle-bracket syntax` and the `as` keyword.

### Angle-Bracket Syntax

```typescript
let someValue: any = "hello, world";
let strLength: number = (<string>someValue).length;
```

In this example, we're telling TypeScript to treat `someValue` as a string temporarily so that we can access its `length` property. This syntax is more common in React projects or older JavaScript codebases.

### The `as` Keyword


```typescript
let someValue: any = "hello, world";
let strLength: number = (someValue as string).length;
```

The `as` syntax is often preferred because it's more readable and less prone to confusion in complex code.


## The Not Null Assertion

TypeScript also supports a special assertion called the "not null assertion," represented by `!`. This assertion tells TypeScript that a variable is not `null` or `undefined`. It can be helpful when you're sure a value exists but TypeScript is unsure.

```typescript
function getLength(someValue: string | null | undefined) {
  return someValue!.length;
}
```

**Caution:** Using the not null assertion when the value can actually be `null` or `undefined` can lead to runtime errors. It should be used sparingly and only when you're absolutely certain about the value's existence.


## The `as const` Assertion

The `as const` assertion is a powerful tool for creating immutable objects and literal types.

Let's see it in action:

```typescript
const colors = {
    red: "RED",
    blue: "BLUE",
} as const; // Assertion

type Color = keyof typeof colors; // Color is "red" | "blue"

const primaryColor: Color = "red"; // Valid
```

Here, `as const` ensures that `colors` is treated as a read-only object, and TypeScript infers `Color` as a literal type.



## 🚧 When **Not** to Use Type Assertions

While type assertions are valuable, they come with risks. Using them carelessly can lead to runtime errors or negate TypeScript's type checking. Here are some scenarios to avoid:

1. **Ignoring Type Safety**: Only use assertions when you are certain of a type. Blindly asserting types can hide bugs.

2. **Avoid the Any Type**: Don't use assertions to escape the `any` type without good reason. It defeats TypeScript's purpose.

3. **Alternative Solutions**: Consider alternative TypeScript features like type guards and narrowing types before resorting to assertions.

## 🤔 When to Use Type Assertions

Type assertions are most helpful in these situations:

- **Interacting with External Data**: When dealing with data from external sources like APIs or user input, assertions can clarify types.

- **Working with Legacy Code**: In older or untyped codebases, type assertions can bridge the gap between TypeScript and JavaScript.

- **Narrowing Types**: When TypeScript can't narrow types automatically, assertions can provide hints to the type checker.

## Examples 

#### 1. Working with Legacy Code

When you're dealing with untyped or loosely typed JavaScript code, type assertions can help you gradually introduce TypeScript without rewriting everything from scratch.

```typescript
let legacyData: any = fetchDataFromLegacyAPI();
let typedData: DataType = legacyData as DataType;
```

#### 2. DOM Manipulation

Working with the Document Object Model (DOM) often involves type casting, as properties and methods can return generic objects.

```typescript
const element = document.getElementById("myElement") as HTMLInputElement;
element.value = "Hello, TypeScript!";
```

#### 3. Testing

In unit tests, you might need to mock certain objects or values. Type assertions can be handy here to temporarily cast them to the expected type.

```typescript
const mockedService = new MockedService() as MyService;
```

#### 4. Interfaces and Complex Types

When dealing with complex object structures, you might need to assert the types to navigate nested properties.

```typescript
interface Person {
  name: string;
  address?: {
    street: string;
    city: string;
  };
}

const data: Person = {
  name: "John",
};

const city = (data.address as { city: string }).city;
```