What is the benefit of using '--strictFunction

2020-08-12 05:52发布

问题:

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?

回答1:

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



回答2:

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