TypeScript, a typed superset of JavaScript, provides advanced typing features that enable developers to write more reliable and maintainable code. This guide will explore TypeScript’s typing system, exploring different ways to define, use, and extend types, including functions, utility types, and more.
Understanding TypeScript types
Basic types
TypeScript offers several basic types which include number
, string
, boolean
, null
, undefined
, symbol
, and bigint
. Here's a simple example:
let isActive: boolean = falselet total: number = 150
TypeScript object types
You can define types for objects by specifying the types of their properties:
type User = {name: stringage: number}const user: User = {name: 'John Doe',age: 30}
TypeScript union types
Union types allow a variable to be one of several types:
type ID = string | numberlet userId: ID = 'abc123' // Can also be a number
Here, the ID type is defined as a union type that can either be a string or a number, allowing for variable use cases where an identifier might be represented in different formats across different contexts or systems. This capability is particularly useful in web development, where user input might be dynamically typed yet still needs to conform to certain expected types, ensuring type safety without losing the versatility needed in JavaScript-based environments. Additionally, union types help in creating more robust interfaces and APIs by explicitly stating that a value can legitimately be one of several types, thereby preventing runtime errors and enhancing code maintainability.
Advanced typing in TypeScript
TypeScript function type
Functions in TypeScript can be typed both in terms of the arguments they take and the values they return:
type GreetFunction = (name: string) => stringconst greet: GreetFunction = (name) => `Hello, ${name}!`
TypeScript interface vs type
While both interface
and type
can be used to define types in TypeScript, there are some differences:
- Interfaces are open and can be extended by declaring the same interface multiple times.
- Types are closed and cannot be reopened to add new properties but can be extended using intersections.
interface Animal {name: string}interface Animal {species: string}type Vehicle = {manufacturer: string}// Extending types using intersectionstype Car = Vehicle & {wheels: number}
TypeScript extend type
You can extend types using intersections as shown above, or for interfaces, simply by extending them:
interface Shape {color: string}interface Circle extends Shape {radius: number}
TypeScript utility types
TypeScript provides several utility types that are extremely useful for common type transformations:
// Partial type makes all properties of an object type optionaltype PartialUser = Partial<User>// Readonly type makes all properties of an object type read-onlytype ReadonlyUser = Readonly<User>
TypeScript map type
TypeScript doesn’t have a specific map
type, but Map
objects can be typed with generics:
const map: Map<string, number> = new Map()map.set('one', 1)
TypeScript type guard
Type guards are a way to provide information about the type of a variable within a conditional block:
function isString(test: any): test is string {return typeof test === 'string'}function example(foo: any) {if (isString(foo)) {console.log("It's a string!", foo.toUpperCase())} else {console.log("It's not a string!", foo)}}
TypeScript best practices
- Prefer interfaces over types when you might need to extend them.
- Use union types to allow for flexibility in your APIs.
- Utilize utility types to manipulate types easily and effectively.
- Implement type guards to ensure variables are of the correct type at runtime.
- Leverage generics to create reusable and flexible components.
For further information on TypeScript typing see the official documentation.