TypeScript Version: 2.4.0
Code
enum Name {
A = "a",
B = "b",
C = "c",
}
// interfaces with computed property names are not supported yet, see https://github.com/Microsoft/TypeScript/issues/5579
interface Item {
/* [Name.A] */ a: string;
/* [Name.B] */ b: number;
/* [Name.C] */ c: boolean;
}
const names: Name[] = [Name.A, Name.B, Name.C];
const item: Item = {
[Name.A]: "a",
[Name.B]: 1,
[Name.C]: true,
};
names.forEach((name: Name) => {
console.log(item[name]);
});
Expected behavior:
No errors are thrown (ideally also when using the commented code with computed interface property names).
Actual behavior:
src/test.ts(16,7): error TS2322: Type '{ [x: string]: string | number | boolean; }' is not assignable to type 'Item'.
Property 'a' is missing in type '{ [x: string]: string | number | boolean; }'.
src/test.ts(23,17): error TS7017: Element implicitly has an 'any' type because type 'Item' has no index signature.
The first error is duplicate of #16687, the second error is new.
I'm not sure if there's a way around the second one other than asserting as keyof typeof item. However, it _should_ work if Name is used for a mapped type definition, or when it's used in a computed key once #5579 works.
just to jump in with related question, what about
enum Name {
A = 'a',
B = 'b'
};
const item: Item = {
[name: Name]: string;
};
gives an error
Error:(6, 38) TS1023:An index signature parameter type must be 'string' or 'number'.
could it be possible to use the above approach to expect the property names to use only values defined in an enum Name
We do handle union types specially in indexing, we should probably do the same for string enums, since they are strictly a union of string literals (and possibly for all union enums).
I would say the change should be as simple as adding a clause to the if statement in getIndexedAccessType.
Given that #16687 already tracks the first part of this, let's use this bug to track the last part, the use of a string enum to index into an object type that has the same keys. Here's a cut-down repro:
```ts
// @noImplicitAny: true
enum Name {
A = "a",
B = "b",
C = "c",
}
interface Item {
a: string;
b: number;
c: boolean;
}
declare const item: Item;
declare const name: Name;
let result = item[name];
Fix is up at #18029
Most helpful comment
We do handle union types specially in indexing, we should probably do the same for string enums, since they are strictly a union of string literals (and possibly for all union enums).
I would say the change should be as simple as adding a clause to the if statement in
getIndexedAccessType.