pleasedesktop
pleasedesktop

Reputation: 1525

Why is TypeScript inconsistent with Object interface property re-assignment?

Common

interface Interface {
  a: number;
}

Scenario 1

let var1: Interface = {
  a: 0
};

const temp = {
  a: 1,
  b: 4
};

var1 = temp; // Compiler is fine with this

Scenario 2

const var2: Interface = {
  a: 2
};

var2.b = 3; // This won't compile

Am I the only one that finds this to be an inconsistency in the way the compiler behaves?

In the first scenario, the compiler doesn't care that the extra b property ends up in the var1 variable.

Yet in the second scenario, the compiler won't permit var2 to have the extra property.

Why does this inconsistency exist?

Is it feasible to eliminate the inconsistency by either:

?

Edit 1

I appreciate that the current behaviour (consistent or inconsistent, depending on your perspective) has arisen because of trade-offs and is now widely adopted.

Yet is there a way (or is it feasible to provide a means) to opt-into preventing scenario 1 in certain cases?

I think what I'm looking for is kind of nominal typing behaviour, rather than structural.

I appreciate that TypeScript made the decision early on to provide structural typing, but I wonder about the feasibility (being a layperson in field of language design), of providing portions of both (structural and nominal).


This question was created with TypeScript version 2.2.1 in mind.

Upvotes: 1

Views: 135

Answers (1)

Nitzan Tomer
Nitzan Tomer

Reputation: 164307

The reason that the first scenario is fine with the compiler is that typescript is based on structural subtyping and the structure of temp satisfies the interface Interface.

However, if you try to access the b property then the compiler will complain:

console.log(var1.b); // error: Property 'b' does not exist on type 'Interface'

The error message is the same as with your 2nd scenario and that's how it is indeed consistent.

Here's an example of how it's useful:

interface Interface {
    a: number;
}

interface BetterInterface {
    a: number;
    b: number;
}

function fn(a: Interface) { }

let a: BetterInterface = {
    a: 0,
    b: 0
};
fn(a);

Notice that BetterInterface doesn't extend Interface, but the compiler infers that from the structure of the object.

Upvotes: 4

Related Questions