1

Having this interface declaration :

interface Thing1 {
    [key: string]: string;
    x: number;
}

Typescript, while compiling, throws an error "TS2411: Property 'x' of type number is not assignable to string index type 'string'"

It sounds legit.

However, as soon as I use an object literal as my indexed type value :

interface Foo {}
interface Thing2 {
    [key: string]: Foo;
    foo: number;
}

... it doesn't complain anymore, which sounds weird to me as number is still a different type than Foo

Any idea on the reason behind this ?

Note: Using Typescript 2.1.5

Frédéric Camblor
  • 1,301
  • 2
  • 12
  • 22

2 Answers2

1

Empty interfaces are compatible with simple types (number, string). Typescript will not complain if you write this:

let c: Foo = 3;

Therefore, in Thing2 typescript inference will still see Foo as compatible with number. However when the index signature is string like in Thing1, all members should be string (as you mentioned).

kdev
  • 705
  • 7
  • 11
1

This is due to the way type compatibility works in TypeScript:

Type compatibility in TypeScript is based on structural subtyping. Structural typing is a way of relating types based solely on their members. This is in contrast with nominal typing.

So, this works:

interface Foo {}
let f: Foo = 3;

Because for each property on {}, there is a property with the same name and type on Number.

That means that this does not work:

interface Foo {}
let f: Foo = 3;
let b: number = f;

The compiler complains about let b: number = f;:

Type 'Foo' is not assignable to type 'number';

Again, from the documentation:

TypeScript’s structural type system was designed based on how JavaScript code is typically written. Because JavaScript widely uses anonymous objects like function expressions and object literals, it’s much more natural to represent the kinds of relationships found in JavaScript libraries with a structural type system instead of a nominal one.

Seamus
  • 4,539
  • 2
  • 32
  • 42
  • I was aware of structural typings, however, I would never thought a number would have the exact same "structure" (in regard of its API) as an object literal. Weird. :-) – Frédéric Camblor Feb 17 '17 at 19:47
  • @Frédéric To be clear, a number does not have the same structure, it's just that for each property on `{}` there is a property with the same name and type on `Number`. I'll clarify the answer. – Seamus Feb 17 '17 at 20:17