Effect CommunityEC
Effect Community4mo ago
3 replies
danielo515

**Type Inference Differences Between Effect.reduce and Array.reduce**

Hey folks! I encountered an interesting type inference issue and I'm curious about why Effect.reduce behaves differently than Array.reduce.

I have nested reducers inside Effect.gen with a helper function that returns a literal union type:

function getUtilizationLevel(count: number) {
  if (count >= highUtilizationThreshold) return "high";
  if (count >= lowUtilizationThreshold) return "medium";
  return "low";
}

// Inside Effect.gen
return Array.reduce(seminarsWithMapping, days, (allDaysAcc, [seminar, maybeEvent]) => { // Type error here in the function
  // ... logic ...
  
  return Array.reduce(eventDays, allDaysAcc, (acc, day) => {
    const utilizationLevel = getUtilizationLevel(newCount);
    
    return {
      ...acc,
      [dateKey]: {
        utilizationLevel: utilizationLevel,   // this is what causes it
        utilization: newCount,
        // ...
      },
    };
  });
});


With Array.reduce, TypeScript widened the return type to a union where the only difference between both variants was that utilizationLevel was
string
in one variant and "high" | "medium" | "low" in the other, creating a union type error:

Type '{ utilizationLevel: string; ... } | { utilizationLevel: "high" | "medium" | "low"; ... }' is not assignable to 
type '{ utilizationLevel: "high" | "medium" | "low"; ... }'


When I used Effect.reduce for both nested reduces, this type error didn't occur.

Adding an explicit return type annotation to getUtilizationLevel fixed the issue with Array.reduce:

function getUtilizationLevel(count: number): "low" | "medium" | "high" {}


Why does Effect.reduce handle type inference better than Array.reduce in this nested context? Is there something about how Effect's type signatures are designed that helps TypeScript narrow types more effectively?
Thanks!
Was this page helpful?