0

My understanding of interfaces in Typescript is that they work similar to interfaces in C#. Meaning, as long as your object implements the properties and methods defined in the interface, you are free to add additional properties in the object.

However, when I type this program into the Typescript Playground, I get an error:

module myTestDemo {
    interface Person {
        name: string;
        age?: number;       
    }

    var p: Person = {
        favoriteMovie: 'Back to the Future',
        name: 'Joe',
        age: 40        
    };    
}

It does not like the line favoriteMovie: 'Back to the Future'. It gives me an error:

'favoriteMovie' does not exist in type 'Person'.

Am I doing something wrong or am I wrong on understanding that objects cannot have additional properties when inheriting an interface?

2
  • Dude typeScript is compiled to plain JS. It's not C#. Commented Oct 20, 2016 at 15:47
  • @mike - I never said Typescript was compiled to C#. I was making an analogy to C#. Commented Oct 20, 2016 at 15:48

2 Answers 2

2

That's not exactly true.

Interfaces work the way you describe them when you use them as a contract for a class:

interface IPerson {
    name: string;
    age?: number;       
}

class Person implements IPerson {
    name: string;
    age: number;
    favoriteMovie: string;
}

(code in playground)

But when you have an object which type is this interface then you need that object to match that interface.
The reason for this is that, taking your example, how would you access the p.favoriteMovie? The compiler doesn't know of this property because it's not in the interface:

var p = {
    favoriteMovie: 'Back to the Future',
    name: 'Joe',
    age: 40        
} as Person;

console.log(p.name); // fine
console.log(p.favoriteMovie); // Error: Property 'favoriteMovie' does not exist on type 'Person'

(code in playground)

Because of that, the compiler will complain if you add properties to an object that don't exist in the interface.

Sign up to request clarification or add additional context in comments.

Comments

1

Objects (specifically, classes) may have additional properties when implementing an interface. That's not quite what you're doing here.

If you throw this code in the playground, it works just fine:

interface Person {
    name: string;
    age?: number;       
}

class p implements Person {
  favoriteMovie: string;
  name: string;
  age?: number;
};  

The difference is whether you're declaring (or using) a type that meets the contract from the interface (i.e., has the same properties or a superset). When using an object literal, you can't just throw in extra properties.

The documentation calls this out:

Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments. If an object literal has any properties that the “target type” doesn’t have, you’ll get an error.

That page also lays out your two options:

  1. Use as to coerce the type (with validation by the compiler, this isn't an unsafe cast):

    const p: Person = {
        favoriteMovie: 'Back to the Future',
        name: 'Joe',
        age: 40        
    } as Person; 
    
  2. Add an index signature to the interface (breaks some type validation):

    interface Person {
        name: string;
        age?: number; 
        [key: string]: number | string;      
    }
    

1 Comment

Thank you! This makes total sense.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.