Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this arrow function in an interface not compile?

What is the difference between Arrow Functions and Regular Functions in implementing Interfaces, so that code A causes compile-time error and code B compiles successfully.

Note: in tsconfig.json all strict type-checking options are enabled, including strictFunctionTypes, BTW it supposed that by enabling strict all strict type-checking options get enabled.

Code A that causes compile time error

interface SomeInterface {
    someFunction: (par1: string | undefined) => string;
}

class SomeClass implements SomeInterface {
    someFunction(par1: string): string    //invalid function signature
    {
        throw new Error('Method not implemented.');
    }
}

And, Code B that compiles successfully.

interface SomeInterface {
    someFunction(par1: string | undefined): string;
}

class SomeClass implements SomeInterface {
    someFunction(par1: string): string    //invalid function signature
    {
        throw new Error("Method not implemented.");
    }
}

Playground Link

like image 917
hossein samarrokhi Avatar asked Dec 08 '21 15:12

hossein samarrokhi


People also ask

Why arrow functions are not hoisted?

An arrow function expression is an anonymous function expression written with the “fat arrow” syntax ( => ). Like traditional function expressions, arrow functions are not hoisted, and so you cannot call them before you declare them. They are also always anonymous—there is no way to name an arrow function.

What does () => mean in JavaScript?

It's a new feature that introduced in ES6 and is called arrow function. The left part denotes the input of a function and the right part the output of that function.

Why arrow functions Cannot be used as constructors?

Arrow functions cannot be used as constructors. They cannot be called with the new keyword. Doing that throws an error indicating that the function is not a constructor. As a result, bindings such as new.

What are the disadvantages of arrow function?

An Arrow function should not be used as methods. An arrow function can not be used as constructors. An arrow function can not use yield within its body. Arrow function cannot be suitable for call apply and bind methods.

Why are arrow functions not used in programming languages?

Most programmers are used to the traditional way of writing functions, and arrow functions change this completely. This makes code harder to read and might take a while for someone newer to grasp the code. Therefore in such circumstances, developers may choose to use regular functions rather than arrow functions.

Why do arrow functions not bind their own this?

Default "this" context Arrow functions do not bind their own this, instead, they inherit the one from the parent scope, which is called "lexical scoping". This makes arrow functions to be a great choice in some scenarios but a very bad one in others If we look at the first example but using arrow functions

What happens to everything before and after the arrow in JavaScript?

Everything before the arrow is arguments of the function and everything after the arrow is always returned as the result of the function. If you need a function that contains multiple statements you can still do this:

Why is the prototype of an arrow function undefined?

It is throwing error — the prototype of an arrow function is undefined . Arrow functions can never be called with the new keyword because they do not have the [ [Construct]] method. Therefore, the prototype property also does not exist for arrow functions.


Video Answer


1 Answers

With --strictFunctionTypes enabled, function types' parameters are checked contravariantly, as required to maintain type safety:

class SomeClass implements SomeInterface { // error here
    someFunction(par1: string): string  
    {
        return par1.toUpperCase();
    }
}

const i: SomeInterface = new SomeClass(); // error here
i.someFunction(undefined); // runtime error here, par1 is undefined

But, as mentioned in the documentation:

During development of this feature, we discovered a large number of inherently unsafe class hierarchies, including some in the DOM. Because of this, the setting only applies to functions written in function syntax, not to those in method syntax.


So method types' parameters are still checked bivariantly, meaning both contavariantly and covariantly, in order to support some common patterns (although perhaps generics or polymorphic this would be a better way to do it for some of these cases). The big example is Array<T>, where people apparently like their covariant arrays:

interface Animal { species: string }
interface Dog extends Animal { bark(): void };
const scooby: Dog = { species: "dog", bark() { console.log("ROOBY ROO or whatevz") } };
const snoopy: Dog = { species: "dog", bark() { console.log("...") } };
function processAnimals(arr: Animal[]) {
    console.log("I got " + arr.map(x => x.species).join(", ") + ".")
};
const dogs = [scooby, snoopy];
processAnimals(dogs); // okay

This is ergonomic and common, but technically the compiler should reject dogs because Dog[] would not be a valid Animal[] (indeed, methods like push() will do bad things like push a Cat into a Dog[] under the hood). But if you go down this route you find out that TypeScript is unsound all over the place in exactly this way, even without function parameters, because property writes are also like this. See this Q/A for more elaboration.


And that means your SomeClass2 produces no error since SomeInterface2 uses method syntax:

class SomeClass2 implements SomeInterface2 { // no error
    someFunction(par1: string): string {
        return par1.toUpperCase();
    }
}

Of course this has exactly the same soundness problem as before:

const i2: SomeInterface2 = new SomeClass2(); // no error
i2.someFunction(undefined); // runtime error, par1 is undefined

But that's just the way it is. Methods are less safe than functions by design, for convenience.

Playground link to code

like image 197
jcalz Avatar answered Nov 24 '22 19:11

jcalz