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,
};