Reputation: 10351
The following TypeScript sample code shows an error Element implicitly has an 'any' type because type '{one: number; two: number;}' has no index signature
in the line const one = obj[prop];
in strict mode.
The compiler allows the line const two = obj[propName];
, so I cannot understand why the error is shown or how to generally speaking access a property of an object using the bracket notation.
const obj = { one: 1, two: 2 };
const props = { one: 'one', two: 'two' };
// it is not possible add or change any properties in the props object
props.zero = 'zero';
props.one = 1;
// prop has the type string
const prop = props.one;
// using the bracket notation fails with the following error message:
// Element implicitly has an 'any' type because type '{one: number; two: number;}' has no index signature.
// const prop: string
const one = obj[prop];
// this works because propName is of type 'two'
const propName = 'two';
const two = obj[propName];
Upvotes: 7
Views: 12849
Reputation: 411
As has been mentioned, the inferred type of props
is {one: string, two: string}
. This means props.one
could be any string (even though we see it is "one"), so when you write obj[props.one]
what you're really accessing is obj[string]
which may not be allowed.
If you made your props an explicit type, you could get around it:
type Props = {one: "one", two: "two"}
, and then use it:
const props: Props = {one: "one", two: "two"}
This way the type of props
is not inferred, and the explicit type of the values is "one" or "two".
But that's annoying to write when what you really want to say is that props
is these exact values. You can tell the compiler not to be clever about the type it infers and use the exact values you specified with as const
:
const obj = { one: 1, two: 2 };
const props = { one: 'one', two: 'two' } as const;
const prop = props.one;
const one = obj[prop];
Now the compiler knows that prop
has the exact value "one" instead of any string
. So it is allowed.
Upvotes: 0
Reputation: 128
Particularly I'm fan of strong type, but
const obj: any
should be ok.
interface test {
one: string;
two: string;
}
const props: test = { one: 'one', two: 'two' }; // {one: string, two: string}
const obj: any = {one: 1, two: 2}; // {one: number, two: number}
const two = obj['two']; // number
const prop = props.one; // string
const one = obj[prop];
Enum Solution
enum numbers {
one = 1,
two = 2
}
const oneStr = numbers[numbers.one];
const one = numbers[oneStr];
Upvotes: -1
Reputation: 5804
Element implicitly has an 'any' type because type '{one: number; two: number;}' has no index signature
Your object has no index signature, it has two named properties.
The compiler allows the line const two = obj['two'];
It allows the names of your properties, that's why obj['two'] and obj['one'] will work.
and the const prop is a string, so I cannot understand why the error is shown
Because a string can have much more values that just 'one' or 'two' and so the compiler cannot ensure, your object[myString]
call will work. It's only valid for two defined string values.
how to generally speaking access a property of an object using the bracket notation.
This would work:
const prop: 'one' | 'two' = 'one';
const test = obj[prop]
You say: prop has value 'one' or 'two' and so the compiler knows your obj[prop] will always be valid.
or
class Example {
one: string;
two: string;
}
const prop: keyof Example = 'one';
const test = obj[prop];
Here keyof(ClassName)
tells the compiler, that your prop var will have an existing property name of Example
.
The above examples assume, that you have an object where only the properties named 'one' and 'two' are valid. If you want to use your object in a "dictionary style", tell typescript about that and add an index signature:
const obj: {[key:string]: string;} = { one: 'one' };
const text = obj[myString];
Now obj allows every string values as key.
Upvotes: 14