Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the benefit of using '--strictFunctionTypes' in Typescript?

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?

like image 679
Helios Avatar asked Aug 09 '18 12:08

Helios


People also ask

Should I use TypeScript strict mode?

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.

How do I make TypeScript stricter?

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.

How do I turn off TypeScript strict?

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" .

What is strict Tsconfig?

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.


2 Answers

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

like image 87
Titian Cernicova-Dragomir Avatar answered Nov 02 '22 22:11

Titian Cernicova-Dragomir


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

like image 35
Kirill Reznikov Avatar answered Nov 02 '22 22:11

Kirill Reznikov