How To Create Custom Types in TypeScript

By Raman Kumar

Updated on Dec 26, 2024

In this tutorial, we'll learn how to create custom types in TypeScript.

TypeScript, a typed superset of JavaScript, introduces features that improve code quality, maintainability, and scalability. One of the most powerful aspects of TypeScript is its type system, which allows you to create custom types tailored to your specific application needs. Custom types help enforce structure, prevent errors, and make code more readable.

We’ll delve deep into creating custom types in TypeScript, learn how to create arrays with a specific number of elements or more, explore custom type syntax, and understand how to compose complex types.

Understanding Custom Types in TypeScript

Custom types in TypeScript are user-defined types that help specify the structure and behavior of data in your application. These types enhance code clarity and ensure that data adheres to a predefined format.

Creating Custom Types

Custom types in TypeScript can be created using type aliases or interfaces. Both allow you to define the structure of an object, but they have subtle differences.

Using Type Aliases

A type alias assigns a name to a specific type. It can represent primitive types, objects, functions, or even other types.

// Primitive type alias
type Username = string;

// Object type alias
type User = {
  id: number;
  username: Username;
  email: string;
  isActive: boolean;
};

// Function type alias
type Callback = (data: string) => void;

Using Interfaces

An interface is specifically used to define the shape of an object. Interfaces are extensible and can be merged, making them ideal for object-oriented programming.

interface User {
  id: number;
  username: string;
  email: string;
  isActive: boolean;
}

// Extending an interface
interface Admin extends User {
  adminLevel: number;
}

Key Difference:

  • Use type for primitives, unions, or tuples.
  • Use interface for defining objects that may need to be extended.

Creating Arrays with a Specific Number of Elements or More

TypeScript allows you to enforce constraints on arrays, such as ensuring they contain a specific number of elements or more.

Tuple Arrays with Fixed Sizes

Tuples in TypeScript are arrays with fixed types and lengths. This is useful when you know the exact number of elements and their types.

type FixedTuple = [string, number, boolean];

const example: FixedTuple = ["Hello", 42, true]; // Valid
// const invalid: FixedTuple = ["Hello", 42]; // Error: Missing element

Using Rest Elements for "At Least" Constraints

To allow arrays with a minimum number of elements but additional ones, use the spread operator (...).

type AtLeastThreeNumbers = [number, number, number, ...number[]];

const validArray: AtLeastThreeNumbers = [1, 2, 3, 4, 5]; // Valid
const anotherValidArray: AtLeastThreeNumbers = [10, 20, 30]; // Valid
// const invalidArray: AtLeastThreeNumbers = [1, 2]; // Error: Too few elements

Combining Tuple and Array Types

You can create types that are partially a tuple and partially an open-ended array.

type MixedArray = [string, ...boolean[]];

const validMixedArray: MixedArray = ["start", true, false, true];

Custom Type Syntax

TypeScript provides flexible syntax for defining custom types, allowing you to express complex relationships.

Union Types

Union types define variables that can hold multiple types.

type Status = "success" | "error" | "loading";

const apiResponse: Status = "success"; // Valid
// const invalidResponse: Status = "completed"; // Error: Invalid value

Intersection Types

Intersection types combine multiple types into one.

type User = {
  id: number;
  username: string;
};

type Admin = {
  adminLevel: number;
};

type SuperAdmin = User & Admin;

const superAdmin: SuperAdmin = {
  id: 1,
  username: "adminUser",
  adminLevel: 5,
};

Optional Properties

You can mark properties as optional using the ? syntax.

type Config = {
  url: string;
  timeout?: number; // Optional
};

const serverConfig: Config = { url: "https://example.com" };

Readonly Properties

Use the readonly modifier to ensure properties cannot be modified after initialization.

type Point = {
  readonly x: number;
  readonly y: number;
};

const p: Point = { x: 10, y: 20 };
// p.x = 15; // Error: Cannot assign to 'x' because it is a read-only property

Composing Types

TypeScript allows you to compose types in powerful ways, enabling you to define complex relationships and constraints.

Mapped Types

Mapped types allow you to create new types by transforming existing ones.

type User = {
  id: number;
  username: string;
  email: string;
};

// Make all properties optional
type PartialUser = {
  [Key in keyof User]?: User[Key];
};

// Readonly mapped type
type ReadonlyUser = {
  readonly [Key in keyof User]: User[Key];
};

Conditional Types

Conditional types enable creating types based on logic.

type IsString<T> = T extends string ? true : false;

type Test1 = IsString<string>; // true
type Test2 = IsString<number>; // false

Template Literal Types

Template literal types allow defining custom string patterns.

type ID = `user_${number}`;

const userId: ID = "user_123"; // Valid
// const invalidId: ID = "user_abc"; // Error

Best Practices

  • Use Type Aliases for Simplicity: Start with type for custom types unless you need the extensibility of interface.
  • Leverage Readonly Properties: Use readonly for properties that should not change.
  • Combine and Compose Types: Use union, intersection, and mapped types to enforce precise constraints.
  • Avoid Overusing Any: Minimize the use of any to maintain the type safety benefits of TypeScript.
  • Use Descriptive Names: Name custom types clearly to reflect their purpose.

Conclusion

Custom types in TypeScript empower developers to write precise, maintainable, and type-safe code. Whether you're working with tuples, enforcing constraints on arrays, or composing types, TypeScript's robust type system ensures clarity and reduces runtime errors. By mastering these concepts, you can take full advantage of TypeScript’s capabilities, making your applications more reliable and easier to understand.

Checkout our instant dedicated servers and Instant KVM VPS plans.