This is the lodash codebase, a modern JavaScript utility library delivering modularity, performance, and extras built with ES modules and TypeScript support.
Your task is to add TypeScript generics and type guards to enforce numeric return types on all numeric aggregation functions (sum, sumBy, mean, meanBy, min, minBy, max, maxBy).
Requirements:
- Create a type guard function
isNumericthat validates if a value can be safely used in numeric operations - Add TypeScript generic constraints to ensure iteratee functions return number | undefined | null
- Enforce return type of
number(including NaN) on all aggregation functions, neverstring - Add overload signatures for both property shorthand ('propName') and callback function patterns
- Ensure type inference works correctly when using property shorthand with typed arrays
Type guard implementation:
- isNumeric(value: unknown): value is number
- Should return false for strings, objects, arrays, symbols
- Should return true for numbers (including NaN, Infinity)
Files to create:
- src/.internal/isNumeric.ts - the type guard function
- src/types/aggregation.ts - shared types and interfaces for aggregation functions
Files to modify:
- src/sumBy.ts - add generic constraints and overloads
- src/meanBy.ts - add generic constraints and overloads
- src/minBy.ts - add generic constraints and overloads
- src/maxBy.ts - add generic constraints and overloads
Example usage with proper type inference: interface Product { name: string; price: number } const products: Product[] = [{ name: 'A', price: 10 }, { name: 'B', price: 20 }] _.sumBy(products, 'price') // infers number return type _.sumBy(products, (p) => p.price) // infers number return type _.sumBy(products, 'name') // TypeScript error: 'name' is not a numeric property
Tests to add:
- Type guard correctly identifies numeric vs non-numeric values
- Generic constraints reject non-numeric property keys at compile time
- Return types are correctly inferred as number
Use no semicolons. Follow existing lodash codebase patterns and conventions.
src/.internal/isNumeric.ts
function isNumeric(value: unknown): value is number {
return typeof value === 'number'
}- Returns
truefor numbers (including NaN, Infinity) - Returns
falsefor strings, objects, arrays, symbols
src/types/aggregation.ts
Key types:
NumericKeys<T>- Extracts keys from type T where the value is numericNumericPropertyShorthand<T>- String keys for property shorthand syntaxNumericIteratee<T>- Callback function type:(value: T) => number | undefined | nullNumericAggregationResult- Alwaysnumberreturn typeExtremumResult<T>-T | undefinedfor min/max operations
src/sumBy.ts - Sum with overloads:
// Property shorthand overload
function sumBy<T extends object>(
array: ArrayLike<T>,
iteratee: NumericPropertyShorthand<T>
): NumericAggregationResult
// Callback function overload
function sumBy<T>(
array: ArrayLike<T>,
iteratee: NumericIteratee<T>
): NumericAggregationResultsrc/meanBy.ts - Mean with same overload pattern
src/minBy.ts - Min returning ExtremumResult<T> (element or undefined)
src/maxBy.ts - Max returning ExtremumResult<T> (element or undefined)
src/sum.ts- Sum of numeric arraysrc/mean.ts- Mean of numeric arraysrc/min.ts- Minimum of numeric arraysrc/max.ts- Maximum of numeric array
src/index.ts - Exports all functions and types
test/types/aggregation.test.ts
Comprehensive tests covering:
- Type guard correctly identifies numeric vs non-numeric values
- Generic constraints reject non-numeric property keys at compile time
- Return types are correctly inferred as number
interface Product { name: string; price: number; quantity: number }
const products: Product[] = [
{ name: 'Apple', price: 10, quantity: 5 },
{ name: 'Banana', price: 20, quantity: 3 }
]
// Property shorthand - TypeScript infers number return type
sumBy(products, 'price') // => 30
meanBy(products, 'price') // => 15
minBy(products, 'price') // => { name: 'Apple', price: 10, quantity: 5 }
maxBy(products, 'price') // => { name: 'Banana', price: 20, quantity: 3 }
// Callback function - TypeScript infers number return type
sumBy(products, (p) => p.price * p.quantity) // => 110
// Non-numeric property - TypeScript ERROR at compile time
sumBy(products, 'name') // Error: 'name' is not assignable to NumericPropertyShorthand<Product>The NumericKeys type extracts only numeric properties:
interface Product { name: string; price: number; quantity: number; discount?: number }
type ProductNumericKeys = NumericKeys<Product>
// Result: 'price' | 'quantity' | 'discount'
// 'name' is excluded because it's a string typetsconfig.json added with:
- ES2020 target
- Strict mode enabled
- Declaration files generated
This implementation was created using Claude Opus 4.5 (model ID: claude-opus-4-5-20251101).
TypeScript compilation passes with no errors:
npx tsc --noEmit
# No output = successlodash % npm run build
> lodash@4.17.23 build
> npm run build:main && npm run build:fp
> lodash@4.17.23 build:main
> node lib/main/build-dist.js
> lodash@4.17.23 build:fp
> node lib/fp/build-dist.js
lodash % npm test
> lodash@4.17.23 pretest
> npm run build
> lodash@4.17.23 build
> npm run build:main && npm run build:fp
> lodash@4.17.23 build:main
> node lib/main/build-dist.js
> lodash@4.17.23 build:fp
> node lib/fp/build-dist.js
> lodash@4.17.23 test
> npm run test:main && npm run test:fp
> lodash@4.17.23 test:main
> node test/test
Running lodash tests.
test.js invoked with arguments: ["/usr/local/Cellar/node/25.2.1/bin/node","/Users/flavioespinoza/Mercor/lodash/test/test"]
----------------------------------------
PASS: 6800 FAIL: 0 TOTAL: 6800
Finished in 10429 milliseconds.
----------------------------------------
> lodash@4.17.23 test:fp
> node test/test-fp
Running lodash/fp tests.
----------------------------------------
PASS: 327 FAIL: 0 TOTAL: 327
Finished in 111 milliseconds.
----------------------------------------