Open In App

How to Create TypeScript Generic Function with Safe Type Matching ?

In TypeScript, generic functions offer a powerful tool for creating flexible and reusable code that can work with various data types. However, ensuring type safety is crucial to prevent runtime errors and maintain code reliability.

These are the following approaches:

Using Type constraints

You can specify constraints on the type parameter to ensure that only certain types are accepted.

Syntax:

function functionName<T>(parameter1: T, parameter2: T, ...): ReturnType {
    // Function body
}

Example: The type constraint { length: number } ensures that only objects with a length property of type number can be passed to the printLength function. This prevents runtime errors by catching invalid types at compile time.

function printLength<T extends { length: number }>
    (obj: T): void {
    console.log("Length:", obj.length);
}

printLength("hello");
printLength([1, 2, 3]);
printLength({ length: 5, width: 3 });
printLength(123);

Output:

Length: 5
Length: 3
Length: 5
 Error: Type 'number' does not have a property 'length'

Using Type inference

TypeScript's type inference mechanism can automatically infer the types based on the provided arguments, reducing the need for explicit type annotations.

Example: TypeScript infers the types of result1, result2, and result3 based on the types of the arguments passed to the identity function. This reduces the need for explicit type annotations and improves code readability.

function identity<T>(arg: T): T {
    return arg;
}

const result1 = identity("hello");
const result2 = identity(123); 
const result3 = identity(true); 

Output:

result1 is of type string
result2 is of type number
result3 is of type boolean

Using Type guards

Type guards are conditional statements that check the type of a value at runtime, ensuring that only values of the expected type are used in the function.

Example: The isString type guard checks if the value is a string at runtime. If it is, the printLength function safely accesses the length property of the string. Otherwise, it handles the case where the value has an invalid type gracefully.

function isString(value: any): value is string {
    return typeof value === "string";
}

function printLength(value: any): void {
    if (isString(value)) {
        console.log("Length:", value.length);
    } else {
        console.log("Invalid type");
    }
}

printLength("hello"); 
printLength(123);

Output:

Length:5
Invalid type

Using Discriminated Unions

Discriminated Unions, also known as tagged unions or algebraic data types, allow TypeScript to narrow down the possible types within a function based on a common discriminator property.

Example: In this example, we define a discriminated union Shape with two possible shapes: Circle and Square. We create a function calculateArea that calculates the area based on the shape passed. TypeScript intelligently infers the types within the function, ensuring type safety.

// Define a discriminated union
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; sideLength: number };

// Function to calculate area based on shape
function calculateArea(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.sideLength ** 2;
    default:
      // Handle unexpected cases
      throw new Error("Invalid shape");
  }
}

const circleArea = calculateArea({ kind: "circle", radius: 5 });
const squareArea = calculateArea({ kind: "square", sideLength: 4 });

console.log("Area of circle:", circleArea);
console.log("Area of square:", squareArea);

Output:

Area of circle: 78.53981633974483
Area of square: 16

Conclusion

Enhancing type safety in TypeScript generic functions is paramount for building reliable and maintainable codebases. By leveraging type constraints, type inference, and type guards, developers can ensure that their generic functions safely handle a variety of data types, preventing runtime errors and improving code readability.

Article Tags :