As I understand it, --strictFunctionTypes
compiler option in Typescript prevents a very common use case of polymorphism from working:
type Handler = (request: Request) => Response
const myHandler: Handler = (request: Request & { extraArg: boolean }) => {
return !!request.extraArg
}
Generally, I assume that all compiler options in the strict
family have some great benefits, but in this case, all I see is that it prevents a very logical behavior from working.
So what are the cases where this option actually gives some benefits? Which harmful scenarios does it prevent?
If you just start a new project I highly recommend using strict mode in TypeScript. It will help you to avoid errors, typos, and mistakes in your code in the future. Strict mode constricts you in ways of writing your code. On other hand, you won't choose the way that will bring you to make a mistake.
You can either set the --strict flag on the command line or specify the strict option within your project's tsconfig. json file to opt into this mode. As of TypeScript 4.3 in August 2021, the --strict flag enables the following eight compiler options: --alwaysStrict.
You can do that by compiling with the --noImplicitUseStrict compiler option—add "noImplicitUseStrict": true to "compilerOptions" in tsconfig. json. Doing so will prevent the compiler from emitting "use strict" .
TypeScript's strict mode parameter can be configurated as several individual parameters for each specific case of type checking. So, basically, if you set the parameter strict to true in tsconfig. json it means that all these strict options are set to true.
It's actually very easy to cause a runtime error without strictFunctionTypes
.
Let's consider the following example:
type Handler = (request: Request) => Response
const myHandler: Handler = (request: Request & { extraArg: string }) => {
// extraArg is required so need to check for null
request.extraArg.toUpperCase();
return null as any;
}
declare let r: Request; // comes from sowhere
myHandler(r); // no need to pass in the extraArg not required by the signature
So in the above example, the function signature requires a Request
so that is all we have to pass in a Request
. But the implementation expects to receive Request & { extraArg: string }
in which extraArg
is required, and access it without having to do a check (after all if it's required the called should have passed it in).
This is the kind of errors strictFunctionTypes
prevents. If an argument in the signature is of a base type, while the implementation expects a derived type, there is no guarantee that the implementation will receive the derived type, as the signature only requires the base type to be passed in
This option fixes what is, in my opinion, a bug in the TypeScript compiler. If it’s not a bug, then it was just a bad design decision and the appearance of a new compiler option proves my point. Let’s start with an example, by default, the next code will be compiled without any problem:
// Focus all your attention on callback signature
// It has date parameter which is a union type
function getCurrentYear(callback: (date: string | number) => void) {
callback((Math.random() > 0.5) ? '2020' : 2020);
}
// note that we ignored the fact that in 50% cases our callback returns string type instead of number.
getCurrentYear((date: string) => {
console.log(date.charAt(0)); // in 50% it is RUNTIME ERROR
});
So that arrow function passed to getCurrentYear narrows down the type of “date” parameter and TypeScript doesn’t care about it. However, the same trick in a different context with variables even without any strict rule would produce an error:
let x: string | number = (Math.random() > 0.5) ? '2020' : 2020;
const y: number = x; // COMPILE TIME ERROR
This makes much more sense and enabling --strictFunctionTypes will ask a compiler to follow the same behavior in callback functions. That definitely will help you to prevent some bugs in a big project.
Source:
https://medium.com/javascript-in-plain-english/what-are-these-strict-compiler-options-in-typescript-part-2-a7e974b13e54
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With