Advanced Patterns

NoInfer<T>

Prevents TypeScript from inferring a type parameter from the usage site where NoInfer is applied, giving priority to other inference sites.

Definition

TypeScript
type NoInfer<T> = intrinsic;

Examples

Prioritizing Inference Site
function createFSM<S extends string>(
  initial: S,
  transitions: Record<S, S[]>,
) {}

// Without NoInfer, S is inferred from both arguments
// With NoInfer on transitions, S is inferred only from initial
function createFSMFixed<S extends string>(
  initial: S,
  transitions: Record<NoInfer<S>, NoInfer<S>[]>,
) {}

// Error: "unknown" is not assignable
createFSMFixed("idle", {
  idle: ["running"],
  running: ["idle", "unknown"], // catches typos!
});
Default Value Matching
function getOrDefault<T>(values: T[], defaultValue: NoInfer<T>): T {
  return values.length > 0 ? values[0] : defaultValue;
}

// T is inferred from 'values' only
getOrDefault([1, 2, 3], 0); // OK
// getOrDefault([1, 2, 3], "oops"); // Error: string not assignable to number
Controlled Type Widening
function emit<T extends string>(
  event: T,
  payload: NoInfer<T> extends "error" ? Error : unknown,
): void {
  console.log(event, payload);
}

emit("error", new Error("fail")); // OK
emit("click", { x: 10 }); // OK

Common Use Cases

  • 1Preventing inference from default values or fallback parameters
  • 2Ensuring type parameters are inferred from primary sources
  • 3State machine definitions where states come from one site
  • 4Function overloads simplified with controlled inference
  • 5Library APIs where user intent should drive inference

Understanding NoInfer<T>

NoInfer<T> is a utility type introduced in TypeScript 5.4 that blocks type inference at a specific usage site. When TypeScript infers a type parameter, it gathers candidates from all positions where that parameter appears. NoInfer tells the compiler to skip a particular position, so the type parameter is inferred from the remaining positions only.

This solves a common problem in generic function design. Consider a function with parameters (values: T[], defaultValue: T)—TypeScript infers T from both parameters. If you pass [1, 2, 3] as values and "fallback" as default, T becomes number | string instead of just number. By changing to (values: T[], defaultValue: NoInfer<T>), T is inferred only from values, and the default must match.

NoInfer is especially valuable for state machine libraries. When defining transitions like Record<State, State[]>, you want State to be inferred from the initial state parameter, not from the transition map. Without NoInfer, typos in the transition map silently widen the State type. With NoInfer on the transitions, typos are caught as errors.

Before NoInfer existed, library authors used workarounds like intersecting with {} or using conditional types to block inference. These hacks were fragile and confusing. NoInfer provides a clean, intentional mechanism for the same purpose.

NoInfer is an intrinsic type, meaning its behavior is built into the compiler rather than expressible in user-land TypeScript. It has no runtime effect—it purely influences type inference during compilation. The resulting type is identical to T; only the inference behavior changes.

Related Types

More Advanced Patterns

Explore TypeScript Types

Browse our complete reference of 30 TypeScript utility types with definitions, examples, and explanations.