Skip to content

Instantly share code, notes, and snippets.

@flavioespinoza
Last active January 23, 2026 00:06
Show Gist options
  • Select an option

  • Save flavioespinoza/9c8349f44c4a5ccd2c0e728da14fcd5b to your computer and use it in GitHub Desktop.

Select an option

Save flavioespinoza/9c8349f44c4a5ccd2c0e728da14fcd5b to your computer and use it in GitHub Desktop.

Conversation Transcript

User

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 isNumeric that 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, never string
  • 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.

Agent

Files Created

Type Guard

src/.internal/isNumeric.ts

function isNumeric(value: unknown): value is number {
  return typeof value === 'number'
}
  • Returns true for numbers (including NaN, Infinity)
  • Returns false for strings, objects, arrays, symbols

Shared Types

src/types/aggregation.ts

Key types:

  • NumericKeys<T> - Extracts keys from type T where the value is numeric
  • NumericPropertyShorthand<T> - String keys for property shorthand syntax
  • NumericIteratee<T> - Callback function type: (value: T) => number | undefined | null
  • NumericAggregationResult - Always number return type
  • ExtremumResult<T> - T | undefined for min/max operations

Aggregation Functions

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>
): NumericAggregationResult

src/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)

Base Functions

  • src/sum.ts - Sum of numeric array
  • src/mean.ts - Mean of numeric array
  • src/min.ts - Minimum of numeric array
  • src/max.ts - Maximum of numeric array

Index Export

src/index.ts - Exports all functions and types

Tests

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

Usage Examples

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>

Type Inference

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 type

Configuration

tsconfig.json added with:

  • ES2020 target
  • Strict mode enabled
  • Declaration files generated

Model Used

This implementation was created using Claude Opus 4.5 (model ID: claude-opus-4-5-20251101).

Verification

TypeScript compilation passes with no errors:

npx tsc --noEmit
# No output = success

Terminal Test Output

lodash % 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.
----------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment