Skip to main content

type-annotations-and-type-assertions

2. Type Annotations and Type Assertions

  • Explore how to explicitly specify types for variables and how to cast types using type assertions.

Absolutely, understanding type annotations and type assertions is crucial for mastering TypeScript. Here are the 20 key points:

1. Basics of Type Annotations

Type annotations allow you to explicitly specify the type for a variable. This adds an extra layer of type checking at compile-time, making your code more robust.

let username: string = "Alice";
let score: number = 75;
let isStudent: boolean = true;

2. Primitive Types

Understand how to annotate primitive types like string, number, boolean. These are the building blocks for type annotations and are straightforward to use.

let name: string = "Bob";
let age: number = 30;
let isActive: boolean = false;

3. Object Types

You can use type annotations for objects to define the shape an object should have. This includes the types of properties and whether they are optional or required.

let user: { name: string; age?: number } = { name: "Carol" }; // age is optional

4. Array Types

Annotate arrays to specify the types of elements they can contain. TypeScript allows you to define arrays of a single type or multiple types.

let fruits: string[] = ["apple", "banana", "cherry"];
let primeNumbers: Array<number> = [2, 3, 5, 7];

5. Tuple Types

Tuples in TypeScript allow you to create an array where the type of a fixed number of elements is known. Know how to annotate tuples for different kinds of scenarios.

let userInfo: [string, number] = ["Alice", 42]; // A tuple with a string and a number

6. Enum Types

Enums are a feature in TypeScript that allow you to define a set of named constants. Learn how to annotate variables to be a specific enum type.

enum Color {
Red,
Green,
Blue,
}
let c: Color = Color.Green;

7. Any and Unknown Types

Understand the any and unknown types, which allow for more flexible code but should be used cautiously, as they can circumvent TypeScript’s type checking.

let flexible: any = 4; // Can be assigned anything
flexible = "maybe a string instead";

let notSure: unknown = 4; // More type-safe than `any`
// You need to perform type-checking before using an `unknown` type
if (typeof notSure === "number") {
// Now we know it's a number
let sum = notSure + 10;
}

8. Union Types

Union types allow a variable to be one of several types. This is useful for variables that can reasonably be more than one type.

let multiType: number | string;
multiType = 20; // valid
multiType = "twenty"; // valid

9. Intersection Types

Learn how to use intersection types to combine multiple types into one. This is useful for mixing multiple functionalities into a single entity.

type Employee = {
name: string;
startDate: Date;
};
type Manager = Employee & {
teamSize: number;
};
let manager: Manager = { name: "Alice", startDate: new Date(), teamSize: 10 };

10. Type Aliases

Type aliases allow you to create custom types based on existing types. They can be used for primitives, objects, arrays, tuples, and any other types.

type Point = {
x: number;
y: number;
};
let drawPoint = (point: Point) => {
// ...
};

11. Type Assertion Syntax

Understand how to perform type assertions using either the as syntax or the angle-bracket syntax. This allows you to override the inferred type.

let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length; // angle-bracket syntax
let strLengthAs: number = (someValue as string).length; // `as` syntax

12. When to Use Type Assertions

Know when it's appropriate to use type assertions. Misuse can lead to runtime errors, as TypeScript will trust your assertion over its own inference.

let someUnknownValue: unknown = "this could be anything";

// The following is a risky move and should be done with caution
let stringLength: number = (someUnknownValue as string).length;
// Make sure to perform runtime checks to avoid errors
if (typeof someUnknownValue === "string") {
stringLength = (someUnknownValue as string).length;
}

13. Type Guards

Learn how to use type guards like typeof and instanceof to narrow down the type within conditional blocks of code.

function isNumber(value: any): value is number {
return typeof value === "number";
}

function doSomething(value: number | string) {
if (isNumber(value)) {
console.log(value.toFixed(2)); // 'value' is treated as a number here
} else {
console.log(value.toUpperCase()); // 'value' is treated as a string here
}
}

14. Literal Types

Literal types allow you to specify that a value must be a specific string or number. Know how to use them for more precise type checking.

let exactValue: "fixed" = "fixed";
// exactValue = "variable"; // Error: Type '"variable"' is not assignable to type '"fixed"'

15. Null and Undefined Types

Learn how to work with null and undefined types in TypeScript, and how to use the strictNullChecks flag for enhanced safety.

let nullableString: string | null = null;
nullableString = "Hello"; // OK
// Without strictNullChecks, you can accidentally assign null to anything

16. Function Types

Annotate function types to specify the types of parameters and the return value. This makes your functions self-documenting and easier to understand.

let myFunction: (input: string) => number;
myFunction = (input) => {
return input.length;
};

17. Overloading Function Types

TypeScript allows function overloading by specifying multiple type signatures for a function. Learn how and when to use this feature.

function getItems(n: number): number[];
function getItems(s: string): string[];
function getItems(arg: any): any[] {
if (typeof arg === "number") {
return new Array(arg).fill(0);
} else {
return new Array(arg.length).fill("item");
}
}

18. Mapped Types

Mapped types allow you to create new types based on existing ones by applying a transformation. They're useful for a wide range of applications like making all properties optional.

type Optional<T> = {
[P in keyof T]?: T[P];
};
type User = {
name: string;
age: number;
};
type OptionalUser = Optional<User>;

19. Conditional Types

Conditional types help you to create complex, dynamic types based on conditions. These are advanced and enable very flexible and powerful type structures.

type IsNumber<T> = T extends number ? "yes" : "no";
type IsNumberResult = IsNumber<42>; // "yes"

20. Utility Types

TypeScript comes with several built-in utility types like Partial, Readonly, Pick, etc., which allow you to transform types in a variety of ways.

interface Todo {
title: string;
description: string;
completed: boolean;
}

type TodoPreview = Pick<Todo, "title" | "completed">;

const todo: TodoPreview = {
title: "Clean room",
completed: false,
};