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

2

14

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?

Highkey answered 9/8, 2018 at 12:41 Comment(1)
Regardless of its type-level effects, I recommend turning this option on for the benefits of improved typechecking-speed alone, as described here: github.com/microsoft/TypeScript/wiki/…Columba
D
26

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

Durston answered 9/8, 2018 at 12:51 Comment(0)
P
5

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

Pinkiepinkish answered 7/5, 2020 at 21:6 Comment(2)
I'm confused by the example code here given that getCurrentYear doesn't actually use the callback. It looks to me like this was not intended for the purposes of your demonstration.Bathrobe
@Bathrobe You are right. there was a typo. Updated codePinkiepinkish

© 2022 - 2024 — McMap. All rights reserved.