Skip to content

enforce-ianitor-check-type

Require Ianitor.Check<T> validators when a TypeScript type gets too complex to trust at runtime.

TypeScript types evaporate at runtime. If your code reads data from a DataStore, RemoteEvent, or any other IO boundary, TypeScript has no way to prove the data matches your type. This rule scores the structural complexity of your types and reports an error when the score crosses a threshold, nudging you to add an Ianitor runtime validator.

  1. Score the type — The rule recursively walks the type, adding weight for nesting depth, property count, unions, intersections, and structural complexity.
  2. Check the threshold — If the score exceeds baseThreshold (default 10), the rule reports an error.
  3. Define an Ianitor schema — Create an Ianitor validator that matches your TypeScript interface.
  4. Derive the type — Use type MyType = Ianitor.Static<typeof myValidator> so the runtime check and the TypeScript type stay in sync.
Incorrect

This type is too deeply nested to trust without a runtime check.

type UserPayload = {
data: {
preferences: {
theme: string;
blurEnabled: boolean;
};
lastLogin: number;
};
};
Correct

Define the validator once and extract the TypeScript type from it.

const userValidator = Ianitor.interface({
data: Ianitor.interface({
preferences: Ianitor.interface({ ... }),
lastLogin: Ianitor.number(),
}),
});
type UserPayload = Ianitor.Static<typeof userValidator>;

The rule accepts a single options object with these fields:

OptionTypeDefaultWhat it controls
baseThresholdnumber10Minimum complexity score before the rule reports.
warnThresholdnumber15Score at which the rule starts warning.
errorThresholdnumber25Score at which the violation becomes an error.
interfacePenaltynumber20Base score added to all interface declarations.
performanceModebooleantrueCap scores at 2x errorThreshold to avoid expensive walks.

Structural weight

Unions, intersections, and optional properties add more weight than simple primitives.

Nesting depth

Each level of nesting multiplies the score via log2(depth + 1).

Property count

Large objects with many fields are penalized to encourage smaller sub-interfaces.

Caching

The rule caches complexity scores per node so re-checking stays cheap.