TypeScript Version: 2.4.0 / nightly (2.5.0-dev.201xxxxx)
Code
type A = {
[index: string]: string;
} & {
body: string | A;
}
var x: A;
var a = x.hi;
var b = x.body; // var b: string | A
let c:A = { body: { body: 'nope'} } // TypeError: property 'body' is incompatible with index signature
Expected behavior:
b should be inferred to be of type string since the index type forces every property of x to be string
Actual behavior:
b is inferred to a more general type that can actually be assigned to it
The actual & expected behaviour section here implies this should be made consistent by being _more_ strict, another option (that I personally would prefer) would be to make it consistent by being less strict instead.
I.e. x.body should still be inferred as string | A, but it should also allow you to provide a body property of type A.
@mhegazy sorry to insist, but I don't understand why this is working as intended. I came up with a similar example that maybe highlights the problem better.
type A = {
[index: string]: string;
} & {
body: string | A;
}
var b: A;
var c: A;
b = { body: '' }
c = { body: '' }
c.body = b // This works
c = { body: b } // TypeError
Expected behavior
I would expect the two constructions to be either both allowed or both disallowed.
Actual behavior
You can construct c one way but not the other.
At the point that you construct a self-contradictory type A, I don't know how to determine what behavior is "expected" and what's not.
I also encountered this problem. I tried to intersect two index signatures and I thought it would unionise the types.
interface A {
a: string;
};
interface B {
b: string;
}
let ab: A & B = {
a: '',
b: '',
} // Working as intended
interface String {
[index: string]: string;
}
interface Numbers {
[index: string]: number;
}
let sn: String & Numbers = {
a: '',
b: 1,
} // Error
http://www.typescriptlang.org/play/#src=%0Ainterface%20String%20%7B%0A%20%20%5Bindex%3A%20string%5D%3A%20string%3B%0A%7D%0A%0Ainterface%20Numbers%20%7B%0A%20%20%5Bindex%3A%20string%5D%3A%20number%3B%0A%7D%0A%0Alet%20sn%3A%20String%20%26%20Numbers%20%3D%20%7B%0A%20%20a%3A%20''%2C%0A%20%20b%3A%201%2C%0A%7D%0A%0Ainterface%20A%20%7B%0A%20%20a%3A%20string%3B%0A%7D%3B%0A%0Ainterface%20B%20%7B%0A%20%20b%3A%20string%3B%0A%7D%0A%0Alet%20ab%3A%20A%20%26%20B%20%3D%20%7B%0A%20%20a%3A%20''%2C%0A%20%20b%3A%20''%2C%0A%7D
My expectation is String & Numbers should resolve to:
interface StringsNumbers {
[index: string]: number | string;
}
I don't think this is working as intended, since removing one property to satisfy the error doesn't resolve the issue. It will just complain that the other property doesn't satisfy the other index signature. Intersecting two index signatures is effectively only accepting {} in this case.
One more unusual thing I encountered:
interface Strings {
[index: string]: string;
}
interface Numbers {
[index: string]: number;
}
interface A {
a: string;
}
function f(ab: Strings & Numbers & A) {
ab.a; // No error
}
f({ a: '' }); // Error
I treats the type differently inside the function versus in argument location.
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.
Most helpful comment
The actual & expected behaviour section here implies this should be made consistent by being _more_ strict, another option (that I personally would prefer) would be to make it consistent by being less strict instead.
I.e.
x.bodyshould still be inferred asstring | A, but it should also allow you to provide abodyproperty of typeA.