Hone logo
Hone
Problems

Implementing a Type-Safe Push Operation for Arrays in TypeScript

This challenge focuses on creating a utility function in TypeScript that allows you to "push" elements onto an array while ensuring type safety. Standard JavaScript's push method doesn't provide strong type checking, potentially leading to runtime errors. This exercise aims to build a function that leverages TypeScript's type system to guarantee the correct type of elements being added to the array.

Problem Description

You are tasked with implementing a function called typeSafePush that takes an array and a variable number of arguments. This function should behave like the standard JavaScript push method, adding the arguments to the end of the array. However, typeSafePush must also ensure that all arguments added to the array are of the same type as the existing elements in the array.

Key Requirements:

  • Type Inference: The function should infer the type of the array elements and enforce that all pushed elements match that type.
  • Variable Arguments: The function should accept a variable number of arguments to be pushed onto the array.
  • Mutation: The function should modify the original array (i.e., it should not return a new array).
  • Return Value: The function should return the new length of the array, just like the standard push method.

Expected Behavior:

  • If the array is empty, the function should accept any type of argument.
  • If the array already contains elements, the function should only accept arguments of the same type as the existing elements.
  • The function should handle cases where the array contains elements of a union type.

Edge Cases to Consider:

  • Empty array.
  • Array with a single element.
  • Array with multiple elements of the same type.
  • Array with elements of a union type (e.g., string | number).
  • Attempting to push an element of an incompatible type.

Examples

Example 1:

Input:
const numbers: number[] = [1, 2, 3];
const newLength = typeSafePush(numbers, 4, 5, 6);

Output:
newLength: 6
numbers: [1, 2, 3, 4, 5, 6]

Explanation: The function successfully adds three numbers to the numbers array, maintaining the number[] type.

Example 2:

Input:
const strings: string[] = ["a", "b"];
const newLength = typeSafePush(strings, "c");

Output:
newLength: 3
strings: ["a", "b", "c"]

Explanation: The function adds a string to the strings array, preserving the string[] type.

Example 3:

Input:
const mixed: (string | number)[] = [1, "hello"];
const newLength = typeSafePush(mixed, 2, "world");

Output:
newLength: 4
mixed: [1, "hello", 2, "world"]

Explanation: The function correctly handles a union type array, adding both a number and a string while maintaining the (string | number)[] type.

Example 4:

Input:
const numbers: number[] = [1, 2, 3];
const newLength = typeSafePush(numbers, "four"); // Attempting to push a string

Output:
// TypeScript compiler error: Argument of type 'string' is not assignable to parameter of type 'number'.

Explanation: TypeScript correctly identifies the type mismatch and prevents the invalid push operation at compile time.

Constraints

  • The function must be written in TypeScript.
  • The function must correctly infer the type of the array elements.
  • The function must not return a new array; it must modify the original array in place.
  • The function must return the new length of the array.
  • The function should handle empty arrays gracefully.
  • The function should be reasonably performant (avoid unnecessary complexity).

Notes

Consider using generics and conditional types to achieve type safety. Think about how to handle the case where the array is initially empty – you'll need to allow any type in that scenario. The key is to leverage TypeScript's type system to enforce type consistency during the push operation. Don't focus on error handling beyond what TypeScript's type system provides; let the compiler catch type errors.

Loading editor...
typescript