Why TypeScript allows you to overload the return type as "any" when implementing interfaces

I'm trying to figure out why TypeScript allows you to overload the return type of a function to type "any" from a more specific type when implementing an interface.

In my case, I am working in Angular and injecting an injected class.

My environment:

Visual Studio 2017

Angular Version 1.5.5

TypeScript Version 2.1.5

The following code compiles without any problem:

export interface IFoo {
    thing: (parameter: number) => string;
}

export class BarService implements IFoo {
    public thing = (parameter: number): any => {
        return { "whatever": parameter };
    }
}
angular.module("FooBar").service("barService", BarService);

      

So now when I try to use the IFoo interface and expect a string to be returned from the "thing" function, the compiler actually allows it to happen!

export class Whatever {
    public foo: IFoo;
    public myString: string;

    static $inject = ["barService"];
    constructor(barService: IFoo) {

        this.foo = barService;

        this.myString = this.foo.thing(0);
    }
}

      

It seems that TypeScript will not compile when the return type is overloaded with the type "any" because users of the interface expect a strongly typed object.

+3


source to share


3 answers


Here's what I put together.

From https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.1 :

All types in TypeScript are subtypes of the same top type called Any Type. Any keyword refers to this type. Any type is one type that can represent any JavaScript value without restriction.

And:

Any type is used to represent any JavaScript value. Any type value supports the same operations as JavaScript value, and minimal static type checking is performed for operations on Any value. In particular, properties of any name can be accessed through Any value, and any value can be called as functions or constructors with any argument list.



Play around:

interface IPerson {
    name: string
} 

class Person implements IPerson {
    name: any;
}

// Error
//class Person2 implements IPerson {
//    name: number;
//}

const person: Person = new Person();
person.name = 3;

let x: number = 3;
x = <any>"hello"; // Works!

//x = "hello"; // Error

      

In the example above, we can see that anyone can be used to override the type system that follows the docs.

I am convinced that this behavior allows flexible non-javascript (flexible) behavior.

+3


source


I'm not a Typescript expert, but based on my understanding any

:

https://www.typescriptlang.org/docs/handbook/basic-types.html

We find this comment on this page:



"We want to move away from type checking and let values ​​pass compile-time checking."

So, I guess when compilers see it any

, it says "I won't validate this type." Ergo, this condition must be sufficient for the compiler to assume that the function is executed correctly.

I used to think about any

how to "accept anything" (which is). But more precisely, it means "Let's assume this is the type you want" from what I've seen. So in this case, the compiler assumes that it is string

for your convenience and allows it to pass compile-time checking.

+2


source


As I see it, there are two places that you would expect from the TypeScript compiler. BarService returns any and all class by assigning the return value from thing () to myString.

The compiler doesn't crash if you return it to your BarService, because in TypeScript you can use any as a substitution for any / all types. A type, of any type in TypeScript, is mainly intended to make it easier to maintain old javascript libraries or code. You can find the Any section here: https://www.typescriptlang.org/docs/handbook/basic-types.html . And yes, it may be abused.

The compiler doesn't work in your Whatever class, because here you are using an interface that actually says that thing () returns a string. The compiler is unaware of BarService when compiling class Whatever.

+1


source







All Articles