I am trying to determine why TypeScript allows you to overload the return type of a function to the type 'any' from a more specific type when implementing an interface.
In my case I am working in Angular and am injecting the implemented class.
My environment:
Visual Studio 2017
Angular Version 1.5.5
TypeScript Version 2.1.5
The following code compiles without any issue:
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 attempt to consume the IFoo interface and am expecting a string to be returned from the 'thing' function call 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 should fail to compile when the return type is overloaded with type 'any' because consumers of the interface are expecting a strongly typed object.
Here is what I have put together.
From https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.1:
All types in TypeScript are subtypes of a single top type called the Any type. The any keyword references this type. The Any type is the one type that can represent any JavaScript value with no constraints.
And also:
The Any type is used to represent any JavaScript value. A value of the Any type supports the same operations as a value in JavaScript and minimal static type checking is performed for operations on Any values. Specifically, properties of any name can be accessed through an Any value and Any values can be called as functions or constructors with any argument list.
Playing 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
We can see in even a simple example above that any can be used to override the type system which follows the docs.
My belief is that this behavior is there to allow the flexibility of javascript's untyped (flexible) behavior.
I'm not an expert on Typescript but based on my understanding of any:
https://www.typescriptlang.org/docs/handbook/basic-types.html
We find this comment on that page:
"We want to opt-out of type-checking and let the values pass through compile-time checks."
So I'm guessing when the compilers sees any, it says "I will not confirm this type". Ergo this condition must be sufficient for the compiler to assume that the function has been implemented correctly.
I used to think of any as "accept anything" (which is does). But more precisely it means "Assume this is the type you want.", from what I've seen. So in this case the compiler assumes it is string for your convenience and allows the compile-time check to pass.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With