Background
By default, TypeScript allows some "looseness" in matching function type signatures, permitting that contravariant and covariant functions are considered compatible. Starting from TypeScript 2.6, the strictFunctionTypes option was introduced, ensuring strict type checking for functions and preventing many classes of errors, especially in large codebases.
Problem
Without strict checking, there may be a situation where a handler function or a callback takes more or more specific parameter types, and this goes unnoticed by the developer. This leads to runtime errors associated with the covariance of return types and contravariance of arguments.
Solution
The strictFunctionTypes option introduces strict contravariance for function parameter types. Now functions are compatible only if the source type parameter is a supertype of the target parameter, and not the other way around.
Code example:
type Animal = { name: string }; type Cat = { name: string; meow: () => void }; let animalHandler: (a: Animal) => void; let catHandler: (c: Cat) => void; animalHandler = catHandler; // Error in strictFunctionTypes: argument is too specific catHandler = animalHandler; // Allowed, Cat is a subtype of Animal
Key features:
Could a handler with a more specific parameter type be assigned before the introduction of strictFunctionTypes?
Yes, before enabling strictFunctionTypes, TypeScript allowed assigning more specific functions instead of general ones, leading to runtime problems:
enum E { A, B } const f: (e: E) => void = (e: E.A) => {} // Without strictFunctionTypes: allowed
How does strictFunctionTypes affect callbacks with optional parameters?
If the parameters of a callback function make some parameters optional, strict checking will not allow using a function with fewer required parameters in a position where a function with more parameters is expected. This prevents situations where a callback does not receive the needed data.
Will there be compatibility issues when enabling strictFunctionTypes in old projects?
Yes, there is a risk of new compilation errors appearing, as many functions and handlers could have been assigned to each other with contravariance violations. This is often encountered in callbacks or when using APIs of third-party libraries without strict typing.
In a large project, event handlers take more specific types (MouseEvent instead of the general Event). This is not detected until the strict option is enabled, leading to errors at runtime with different event sources.
Pros:
Cons:
The project has used strictFunctionTypes from the beginning. When adding new handlers, all discrepancies between types are automatically detected by the compiler. The code becomes more resilient to typos and is easier to maintain.
Pros:
Cons: