I can't understand why the first two printouts work, while the other two produce an error.
const index1 = "name";
const holder: { field: string; } = { field: "name" };
const index2 = holder.field;
const target = { name: "beep" } as MyType;
console.log(target["name"]);
console.log(target[index1]);
console.log(target[holder.field]);
console.log(target[index2]);
The error says:
TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'MyType'.
No index signature with a parameter of type 'string' was found on type 'MyType'.
How can I get a field by a variable name coming from a non-constant?
I haven't found good answers addressing this specific issue in a way that I recognized. Most confusing is the fact that I am using a string to get the field in the object in both cases. The only difference is the const
declaration.
I've tried adding as const
according to an example without any difference.
The field value comes from this interface. It definitely is a string. In the sample above, I even simplified the type definition.
export interface SortInfo {
field: string;
direction: number;
}
The object itself that I'm trying to get the field from is declared by this interface.
export interface MyType {
id: string;
name: string;
type: number;
...
}
TypeScript is telling that it cannot be sure that the key you are using is valid for this object.
Just as target["foobar"]
doesn't compile, so does target[key]
if the type of key
is string
.
You need the type of your key to be keyof typeof target
, or in your case keyof MyType
, which is "id" | "name" | "type" | ...
You can define holder
as { field: keyof MyType; }
:
const holder: { field: keyof MyType; } = { field: "name" };
console.log(target[holder.field]); // This works fine
If that type should really be SortInfo
, then you can use
export interface SortInfo {
field: keyof MyType;
direction: number;
}
And of course if MyType
can be different things you'd use generics:
export interface SortInfo<T> {
field: keyof T;
direction: number;
}