TypeScript 2.6 checks what a callback can safely accept
TypeScript 2.6 adds strictFunctionTypes, checking function parameters contravariantly while retaining a method exception for common JavaScript patterns.
A function that handles dogs cannot safely replace a function that promises to handle any animal. The caller of the broader interface is entitled to supply an animal without dog-specific properties. Looking only at the subtype relationship between the parameter names can lead to the wrong assignment rule. TypeScript 2.6 adds strictFunctionTypes to check the relationship in the direction required by the caller's promise.
The October 31 release announcement explains that this mode compares parameters contravariantly for function types that do not originate from methods. It is opt-in independently and enabled by the strict preset. The method exception is part of the design, preserving important compatibility patterns in arrays and the DOM while allowing stricter checking for many callbacks.
I find this useful because framework code frequently passes behavior into another library. A callback's parameter annotation is a claim about what the callback can process, and the receiving API makes its own claim about what it may supply. TypeScript can help only when it checks that those two claims agree.
Substitution determines the direction
Suppose an animal type has a general property and a dog type adds another. The two function types describe different requirements for their callers. A function accepting any animal can process a dog because the dog has the general animal properties. A function requiring a dog may access properties absent from another animal.
interface Animal {
name: string;
}
interface Dog extends Animal {
bark(): void;
}
let handleAnimal: (animal: Animal) => void;
let handleDog = (dog: Dog) => dog.bark();
// Rejected with strictFunctionTypes:
// handleAnimal = handleDog;
If that assignment were accepted, the name handleAnimal would promise a broader input than the assigned function supports. Calling it with an animal lacking bark would violate the implementation's requirement. The error is in the substitution, even though assigning a dog value to an animal variable is ordinarily valid.
Function parameter compatibility reverses that familiar direction. To substitute a function requiring Animal where a function requiring Dog is expected, the check asks whether the caller's dog can be used as an animal. It can. To substitute the dog-only function for the animal handler, the check would need every animal to be usable as a dog. That does not hold.
The announcement calls this reversal contravariance. This term names the assignment relationship without introducing an extra runtime mechanism. Emitted JavaScript still calls the function with a value. Checking rejects a declaration of compatibility that would let the caller supply a value the implementation cannot handle.
Return values have a different relationship
The release contrasts parameter checking with return-type checking. A function returning a more specific value can satisfy an interface promising a broader result. Returning a dog where the caller expects an animal gives the caller the animal properties it needs. The direction does not reverse in that case, which the announcement calls covariance.
This difference explains why treating every occurrence of a type parameter the same way is unreliable. A function can consume a value through a parameter and produce a value through its return. The safe relationship depends on which side of that operation the caller occupies. A declaration that looks symmetric on the page can contain requirements pointing in different directions.
The same reasoning applies to callbacks passed into promises. Rosenwasser's example has a Promise<string | number> and a callback that calls toLowerCase on a string parameter. That promise may provide a number, so a string-only callback is insufficient. Under the new flag, the checker compares the promised input against the callback's actual accepted type and rejects the mismatch.
That diagnostic identifies a concrete application error. Annotating the callback's parameter as a string does not force the promise to resolve with a string. The callback must handle the values the API can provide, or the program must establish a narrower promise result before using that callback. The new check prevents an annotation from concealing the broader input.
Bivariance accepted some unsafe relationships
The announcement describes TypeScript's previous general parameter comparison as bivariant, allowing compatibility in either direction where a sufficient relationship existed. That catches wholly unrelated types but permits some substitutions that cannot be justified for every possible caller. The animal-handler example illustrates such a case.
This policy arose from compatibility with JavaScript patterns, not because reversing the parameter direction was unknown. The release explains that strict contravariance everywhere would make common structures difficult to use. An array both produces elements through operations such as pop and consumes them through operations such as push. Applying strict opposing requirements throughout that structure would make the element type invariant.
In that model, Array<Dog> would not be assignable to Array<Animal>. The announcement identifies that outcome as challenging for established uses, alongside methods in the DOM hierarchy. The new mode therefore draws a boundary around which function types receive the stricter comparison. Understanding that boundary is necessary before claiming the flag establishes universal soundness.
Methods retain an exception
strictFunctionTypes excludes function types originating from methods. The release explicitly presents this as a way to preserve event-handler and array patterns while tightening other function relationships. A function-valued property and a method declaration can consequently have different checking behavior under the new mode, even if both appear callable to application code.
That distinction is a real declaration-design consideration. An API author should choose syntax that accurately describes the interface, with an understanding of the compatibility consequences. Changing a declaration's form solely to avoid a diagnostic can change which relationships the checker is able to reject. The exception should remain visible in explanations of the flag's guarantees.
I prefer a stated compatibility tradeoff to a broad claim that the compiler now catches every unsafe callback. The useful gain is that many ordinary function substitutions receive the stricter check. The retained method rule explains why some similar-looking cases still behave differently and prevents a developer from drawing the wrong conclusion from one successful example.
The strict preset gains a new check
The TypeScript 2.3 announcement introduced strict as a way to enable a recommended group of settings. TypeScript 2.6 adds function-parameter checking to that policy. Projects already using strict therefore receive the new rule when they move to this compiler version.
A project can explicitly set strictFunctionTypes to false while retaining strict. The release shows this override in configuration. That separates a deliberate exception from disabling the entire preset. The existence of an override is a compatibility facility, while the underlying callback still needs to satisfy the runtime expectations of the API receiving it.
This also demonstrates why the preset should be understood as an evolving policy. The compiler's version is part of the meaning of strict: true. A build can report new errors after an upgrade without any application source changing because the enabled check set has expanded. The announcement identifies the new member of that set and explains how to opt out of it specifically.
Faster watching tracks affected files
The release's other major implementation change concerns watch-mode output. Given changed files, the compiler determines the set of files those changes may affect. Only that set goes through the transformation and emission passes. The announcement identifies large codebases using ECMAScript modules as a context where this can matter.
This is a more specific claim than saying every TypeScript operation is faster. It describes incremental work in --watch mode, particularly the passes that transform source and print output. A project using another build tool does not automatically receive the same integration. The announcement says an API for other tools is intended for a future release, so that part remains planned as of today.
The announcement also describes editor assistance for adding annotations from JSDoc and inferring types at use sites. Those operations help express information already present in source or its usage. They complement stricter compatibility checks by giving developers another route to make the intended interface explicit before comparing it with a caller's expectations.
Suppression applies to the next line
TypeScript 2.6 also brings // @ts-ignore into TypeScript files. The comment suppresses errors on the following line. The announcement motivates it through migration from JavaScript and checks in legacy code, while encouraging an explanation of why a suppression is needed. This is a local escape from reporting, without changing the operation's runtime behavior.
Its scope is broader than proving one specific type relationship acceptable. Suppressing a line removes its reported errors, so it does not establish that the callback on that line can handle every value its API supplies. The stricter function rule is useful precisely because it explains such relationships before execution. Where a program retains a suppression, the source still needs an accurate account of the input the callback may receive.