TypeScript Typed Array Utilities
This challenge focuses on building robust and type-safe utility functions for working with arrays in TypeScript. You'll create functions that can safely transform and manipulate array elements while preserving and enforcing their types, making your code more predictable and reducing runtime errors.
Problem Description
Your task is to implement a set of generic TypeScript functions that operate on arrays. These functions should be designed to handle various common array operations, ensuring type safety throughout. Specifically, you need to implement the following:
-
mapTyped<T, U>(array: T[], mapper: (item: T) => U): U[]: A function that maps over an array, applying a transformation function to each element and returning a new array of the transformed elements. The types of the original elements (T) and the transformed elements (U) should be clearly defined. -
filterTyped<T>(array: T[], predicate: (item: T) => boolean): T[]: A function that filters an array based on a predicate function. It should return a new array containing only the elements for which the predicate returnstrue. The type of the elements in the returned array should be the same as the input array. -
reduceTyped<T, U>(array: T[], reducer: (accumulator: U, currentValue: T) => U, initialValue: U): U: A function that reduces an array to a single value. It should accept a reducer function and an initial value for the accumulator. The types of the array elements (T) and the accumulator/result (U) should be distinct and properly handled. -
findTyped<T>(array: T[], predicate: (item: T) => boolean): T | undefined: A function that searches an array for the first element that satisfies a provided testing function. It should return the found element, orundefinedif no element satisfies the test.
Key Requirements:
- All functions must be generic and accept type parameters to define the types of array elements and, where applicable, the transformation or accumulator types.
- The return type of each function must accurately reflect the types of its output.
- The functions should not mutate the original arrays; they should always return new arrays (except for
findTyped).
Expected Behavior:
mapTypedshould behave like the built-inArray.prototype.map, but with explicit generic type arguments.filterTypedshould behave like the built-inArray.prototype.filter, but with explicit generic type arguments.reduceTypedshould behave like the built-inArray.prototype.reduce, but with explicit generic type arguments for both the array elements and the accumulator.findTypedshould behave like the built-inArray.prototype.find, but with explicit generic type arguments.
Edge Cases:
- Empty input arrays.
- Predicates/mappers that return
nullorundefined. reduceTypedwith an empty array and no initial value (though this specific implementation requires an initial value).
Examples
Example 1: mapTyped
const numbers = [1, 2, 3];
const stringifiedNumbers = mapTyped(numbers, (num) => `Number: ${num}`);
// Expected output: ["Number: 1", "Number: 2", "Number: 3"]
// Type of stringifiedNumbers: string[]
Example 2: filterTyped
const ages = [25, 17, 30, 15, 19];
const adults = filterTyped(ages, (age) => age >= 18);
// Expected output: [25, 30, 19]
// Type of adults: number[]
Example 3: reduceTyped
const prices = [10.5, 20.25, 5.0];
const total = reduceTyped(prices, (sum, price) => sum + price, 0);
// Expected output: 35.75
// Type of total: number
const words = ["hello", " ", "world"];
const sentence = reduceTyped(words, (acc, word) => acc + word, "");
// Expected output: "hello world"
// Type of sentence: string
Example 4: findTyped
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" },
];
const bob = findTyped(users, (user) => user.name === "Bob");
// Expected output: { id: 2, name: "Bob" }
// Type of bob: { id: number; name: string; } | undefined
const nonExistent = findTyped(users, (user) => user.name === "David");
// Expected output: undefined
// Type of nonExistent: { id: number; name: string; } | undefined
Example 5: mapTyped with complex types
interface Person {
firstName: string;
lastName: string;
}
const people: Person[] = [
{ firstName: "Jane", lastName: "Doe" },
{ firstName: "John", lastName: "Smith" },
];
const fullNames = mapTyped(people, (person) => `${person.firstName} ${person.lastName}`);
// Expected output: ["Jane Doe", "John Smith"]
// Type of fullNames: string[]
Constraints
- The input
arrayfor all functions will be a valid JavaScript array. - The
mapper,predicate, andreducerfunctions provided as arguments will be valid JavaScript functions. initialValueforreduceTypedwill be provided.- Performance is not a critical concern for this challenge; focus on correctness and type safety.
Notes
- Remember to utilize TypeScript's generic type parameters effectively to infer and enforce types.
- Consider the return type of
findTypedcarefully, as it might not find a matching element. - This challenge is designed to reinforce your understanding of generics, function signatures, and type inference in TypeScript.