Skip to content

Empty interface allow any object? #14606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mleko opened this issue Mar 12, 2017 · 7 comments
Closed

Empty interface allow any object? #14606

mleko opened this issue Mar 12, 2017 · 7 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@mleko
Copy link
Contributor

mleko commented Mar 12, 2017

I posted question on SO but haven't received definite answer so I assume this might be a bug.

Why empty interface doesn't require object to be empty?

interface A {};
const a: A = {a: 1};
console.log(a);

is valid code and will output { a: 1 }.

I would assume that adding optional property should work fine, but

interface A {};
interface B extends A {
	b?: any;
}
const a: B = {a: 1};
console.log(a);

ends with error Type '{ a: number; }' is not assignable to type 'B'.

  • If interface define what properties object must have, B case should work fine, all required properties are present.
  • If interface define what properties object can have, A case should result in error, a is not defined in interface.

Non empty interface defines both what object can and must have.
Empty interface behaves like any.

Is there explanation why empty interface behaves like this? Is this intentional or it's just a bug?

Expected behavior:

interface A {};
const a: A = {a: 1};
console.log(a);

error Type '{ a: number; }' is not assignable to type 'A'.

Actual behavior:

interface A {};
const a: A = {a: 1};
console.log(a);

{ a: 1 }

@ahejlsberg
Copy link
Member

In general, subtyping permits an object to have additional properties in an assignment. However, in the specific case of an object literal source object and a non-empty target type, TypeScript disallows excess properties in the object literal as an added safeguard. See #3823 for the rationale. The excess property check is not performed when the target is an empty object type since it is rarely the intent to only allow empty objects in that case.

@ahejlsberg ahejlsberg added the Working as Intended The behavior described is the intended behavior; this is not a bug label Mar 12, 2017
@mleko
Copy link
Contributor Author

mleko commented Mar 13, 2017

Actually this is quite inconsistent

interface A {};
const a: A = {a: 3};
console.log(a.a)

gives

(3,15): Property 'a' does not exist on type 'A'.

interface A {};
const a: A = 1;
console.log(a + 1)

results in

(3,13): Operator '+' cannot be applied to types 'A' and '1'.

No.1 is kinda expected
No.2 IMHO should end with

(2,7): Type '1' is not assignable to type 'A'.

since A is object type

Bug, quirk or feature?

@RyanCavanaugh
Copy link
Member

"Type '1' is not assignable to type 'A'." is the completely wrong error. Assignability is not used to check the + operator, nor is it the correct thing to do. For example, { } + { } is invalid even though the operands have identical type.

@mleko
Copy link
Contributor Author

mleko commented Mar 13, 2017

What is my concern
No. 1 - I can put anything in, but take nothing out - blackhole type
No. 2 - attempt to assign number to object type (line 2) should result in error; IMHO

@aluanhaddad
Copy link
Contributor

@mleko

No. 1 - I can put anything in, but take nothing out - blackhole type

Right but that is what an explicit type annotation on an initialized binding does, it blocks type inference, overriding the inferred type with that of the annotation. Out of curiosity, why are you placing a type annotation on a binding that has an initializer? TypeScript's type inference is amazing, take advantage of it.

// works perfectly and is 100% well typed
const a = {a: 3};
console.log(a.a);

@mleko
Copy link
Contributor Author

mleko commented Mar 15, 2017

@aluanhaddad
I define configurations for several environments. Explicit variable type ensures there are no misspelled properties, as all configurations share same interface.

@aluanhaddad
Copy link
Contributor

aluanhaddad commented Mar 16, 2017

Well you would get a type error at the use site if there was a misspelled property but, that aside, a well specified interface is certainly valuable, in which case you'll need to declare all the properties it holds and then will be no type errors. So I'm not sure I understand how you would want the current behavior to be different.

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

5 participants