TypeScript 5.5 beta infers what a filter actually excludes
TypeScript can infer type predicates from qualifying boolean functions. The false result matters as much as the true result, which explains why filtering numbers by truthiness remains ambiguous.
Filtering out undefined is an ordinary JavaScript operation, but the resulting array's type has not always reflected what the callback established. The TypeScript 5.5 beta, announced April 25, infers type predicates for qualifying functions. That lets array filtering carry a refinement into the element type without requiring an explicit predicate annotation.
The interesting constraint is that a predicate describes both outcomes. A function claiming that its parameter is a string when it returns true also tells the checker something when it returns false. That second implication prevents several tempting but incorrect inferences. The feature is therefore more specific than treating every boolean callback as an explanation of the values it accepts.
I appreciate TypeScript when it captures an ordinary program's meaning without requiring parallel type machinery. Filtering missing results is common enough that a separate annotation can feel like repeating the same condition. Having the compiler derive the relationship is useful, provided it also recognizes when a condition does not justify that relationship.
A boolean result can describe a parameter refinement
The beta lists several conditions for inference. The function must lack an explicit return annotation, have a single return with no implicit return paths, avoid mutating its parameter, and return a boolean expression related to a refinement. A simple presence check meets those requirements. This example retains zero as a valid value:
const readings: (number | undefined)[] = [0, undefined, 12];
const present = readings.filter(value => value !== undefined);
present.push(15);
present.push(undefined); // Type error with strictNullChecks
The callback can receive a predicate signature saying that a successful result establishes number. An array filter declaration already has an overload that uses such a predicate. The new work is inferring that signature from the callback body, connecting existing control-flow information to an existing library declaration.
That mechanism explains why the runtime behavior does not change. JavaScript still calls the same filter callback and retains values for which it returns true. The checker now describes the result more precisely. Code that previously needed a handwritten predicate can receive the same narrowing from its implementation when the inference conditions hold.
Truthiness loses a meaningful numeric value
Replacing the condition with !!value changes the logical claim. A true result establishes that the optional numeric input is a number. A false result can mean either undefined or zero. The false branch therefore cannot establish that the input is outside the entire number type. Inferring a full predicate would discard that distinction.
This matters in real calculations because filtering zero out changes the data. A presence filter should remove missing values, while a truthiness filter also removes a valid numeric observation. The beta announcement uses this ambiguity to explain why the compiler declines the predicate. The remaining error can identify a mistake in the condition instead of merely demanding more syntax from the author.
Dan Vanderkam's account of implementing the feature describes a related counterexample. A function combines a string check with an unrelated condition that can fail. Success implies a string, but failure does not exclude strings. Treating that function as a predicate would give a caller an invalid refinement in its false branch. The implementation had to account for that implication.
A more precise array type can reject a later mutation
The beta notes that stronger inference can break code which deliberately reintroduces an excluded value. Filtering nulls now produces an array whose element type excludes null. Pushing null into it then fails, even though an earlier compiler accepted the mutation. The appropriate type depends on whether the filtered array is intended to stay narrow.
An explicit annotation can retain a broader mutation contract when that is intentional. This does not change what filter returns. It describes what values the receiving variable is allowed to contain afterwards. The distinction between the initial result and future mutation is useful because inference normally chooses the information available from the initializer, not every operation an author might later want to perform.
Regular expressions receive separate static checking
The beta also adds basic checking for regular-expression literals. It can diagnose unmatched syntax, nonexistent backreferences, and features incompatible with the configured ECMAScript target. Named capture groups, for example, require an appropriate target. This is another improvement in understanding existing JavaScript syntax, without transforming the expression into an implementation for older runtimes.
The documented limit is literal syntax. A string passed to new RegExp does not receive the same checking, even when the string is itself a literal. The compiler therefore has a specific analysis boundary. Code generation and dynamically assembled expressions remain separate concerns from the source-level literal checks introduced here.
I regard the predicate feature as the more consequential of these changes for routine application code. It removes annotations where the condition already supplies enough information and preserves uncertainty where it does not. The zero-versus-missing case makes that limit understandable. A developer can examine the callback's false result and see why the checker cannot safely infer the stronger claim.