prefer-type-fest-union-to-intersection
Prefer UnionToIntersection from type-fest over custom distributive conditional helpers that convert unions into intersections.
This rule lives only in the experimental preset and reports without autofixing.
Targeted pattern scopeโ
This rule focuses on the canonical conditional-type recipe that turns a union into an intersection by distributing a function wrapper over the union and then inferring the merged parameter type.
(Union extends unknown ? (value: Union) => void : never) extends (value: infer Intersection) => void ? Intersection : never- the common assignable variant that returns
Intersection & Union
It intentionally skips unrelated conditional helpers and non-canonical extraction tricks to keep reporting narrow.
What this rule reportsโ
This rule reports conditional helpers when all of the following are true:
- the inner conditional distributes over the same
Uniontype withextends unknownorextends any - the inner true branch wraps that union in a single-parameter function type
- the outer conditional infers the merged parameter type from a single-parameter function type
- the outer true branch returns either the inferred type alone or the inferred type intersected with the original union
The rule is currently report-only. It does not autofix or suggest a replacement yet.
Why this rule existsโ
UnionToIntersection<Union> states the intent directly.
- Readers do not need to unpack a dense conditional-type trick.
- The canonical helper is easier to search for across a codebase.
- Type-Fest owns the edge cases and maintenance burden for the pattern.
โ Incorrectโ
type MergeUnion<Union> =
(Union extends unknown ? (value: Union) => void : never) extends
(value: infer Intersection) => void
? Intersection
: never;
โ Correctโ
import type {UnionToIntersection} from "type-fest";
type MergeUnion<Union> = UnionToIntersection<Union>;
Behavior and migration notesโ
- This rule only reports the narrow distributive function-wrapper pattern.
- It also accepts the
Intersection & Unionvariant because that still expresses the same underlying conversion. - It ignores unrelated conditionals and other custom extraction helpers that do not match the canonical structure closely enough.
Additional examplesโ
โ Incorrect โ Additional exampleโ
type MergeUnion<Union> =
(Union extends any ? (value: Union) => void : never) extends
(value: infer Intersection) => void
? Intersection & Union
: never;
โ Correct โ Additional exampleโ
import type {UnionToIntersection} from "type-fest";
type MergeUnion<Union> = UnionToIntersection<Union>;
ESLint flat config exampleโ
import typefest from "eslint-plugin-typefest";
export default [typefest.configs.experimental];
When not to use itโ
Disable this rule if your project intentionally prefers hand-written conditional-type recipes for educational reasons or if you are using a different local utility type and do not want to standardize on Type-Fest.
Package documentationโ
TypeFest package documentation:
Source file: source/union-to-intersection.d.ts
import type {UnionToIntersection} from "type-fest";
type Union = {a: string} | {b: number};
type Combined = UnionToIntersection<Union>;
//=> {a: string} & {b: number}
Rule catalog ID: R089