TypeScript allows you to define types for variables, function parameters, and return values at compile - time. This means that the compiler can check for type errors before the code is run. For example:
// Define a variable with a specific type
let num: number = 10;
// This will cause a compilation error
// num = "hello";
TypeScript can automatically infer the type of a variable based on its initial value. For instance:
// TypeScript infers the type of 'message' as string
let message = "Hello, TypeScript!";
Union types allow a variable to have one of several types. You can use the |
operator to define a union type.
let value: number | string;
value = 10;
value = "ten";
When defining functions, you can specify the types of parameters and the return type. This makes the function’s behavior more predictable.
function add(a: number, b: number): number {
return a + b;
}
const result = add(3, 5);
Interfaces are used to define the structure of an object. They can be used to enforce a certain shape for objects passed as parameters or returned from functions.
interface Person {
name: string;
age: number;
}
function printPerson(person: Person) {
console.log(`${person.name} is ${person.age} years old.`);
}
const john: Person = { name: "John", age: 30 };
printPerson(john);
Enums are used to define a set of named constants. They make the code more readable and less error - prone.
enum Color {
Red,
Green,
Blue
}
let myColor: Color = Color.Green;
any
TypeThe any
type in TypeScript bypasses type checking. While it can be useful in some cases, overusing it defeats the purpose of type safety. For example:
// Avoid this
let data: any = "Some data";
data = 10;
Type assertion allows you to tell the compiler that a variable is of a certain type. However, it should be used sparingly because it can hide type errors.
let value: any = "hello";
let length: number = (value as string).length;
You can use type guards to perform type - specific operations within conditional statements.
function printValue(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase());
} else {
console.log(value.toFixed(2));
}
}
Mark properties as readonly
when they should not be modified after object creation. This helps prevent accidental mutations.
interface Point {
readonly x: number;
readonly y: number;
}
const p: Point = { x: 10, y: 20 };
// This will cause a compilation error
// p.x = 30;
Optional chaining (?.
) and nullish coalescing (??
) operators help handle optional properties and nullish values in a type - safe way.
interface User {
address?: {
street?: string;
};
}
const user: User = {};
const street = user.address?.street?? "Unknown";
Unit tests can help ensure that the types are being used correctly in your code. You can use testing frameworks like Jest to write tests that verify the behavior of functions with different types of inputs.
TypeScript’s type safety features are a powerful tool for developers. By understanding the fundamental concepts, using the right usage methods, following common practices, and adopting best practices, you can write more reliable, maintainable, and error - free code. Remember to avoid overusing features that bypass type checking and always strive to make your code as type - safe as possible.