Question
I'm using TypeScript in a React project and getting this error when filtering an array:
.filter(({ name }) => plotOptions[name]);
TypeScript reports:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ train_1: boolean; train_2: boolean; train_3: boolean; train_4: boolean; }'.
No index signature with a parameter of type 'string' was found on type '{ train_1: boolean; train_2: boolean; train_3: boolean; train_4: boolean; }'.
I tried adding an index signature based on an article about indexing objects in TypeScript, but the error still remains.
Here is the component:
import React, { Component } from "react";
import createPlotlyComponent from "react-plotly.js/factory";
import Plotly from "plotly.js-basic-dist";
const Plot = createPlotlyComponent(Plotly);
interface IProps {
data: any;
}
type PlotOptions = {
train_1: boolean;
train_2: boolean;
train_3: boolean;
train_4: boolean;
};
interface IState {
plotOptions: PlotOptions;
}
type TrainName = keyof PlotOptions;
interface TrainInfo {
name: TrainName;
x: number[];
y: number[];
type: string;
mode: string;
}
class FiltrationPlots extends <, > {
: = {
: {
: ,
: ,
: ,
:
}
};
() {
{ data } = .;
{ plotOptions } = .;
(data.) {
: [] = [
{
: ,
: data..( i[]),
: data..( i[]),
: ,
:
},
{
: ,
: data..( i[]),
: data..( i[]),
: ,
:
},
{
: ,
: data..( i[]),
: data..( i[]),
: ,
:
},
{
: ,
: data..( i[]),
: data..( i[]),
: ,
:
}
].( plotOptions[name]);
(
);
}
;
}
}
;
Why does TypeScript reject plotOptions[name], and how should this be typed correctly?
Short Answer
By the end of this page, you will understand why TypeScript does not allow indexing a specifically typed object with a plain string, how keyof solves this, and how to correctly type related React data structures so object access like plotOptions[name] is safe and accepted by the compiler.
Concept
TypeScript distinguishes between:
- any string: could be
"train_1","hello", or"does_not_exist" - specific known keys: such as
"train_1" | "train_2" | "train_3" | "train_4"
Your plotOptions object has a fixed shape:
type PlotOptions = {
train_1: boolean;
train_2: boolean;
train_3: boolean;
train_4: boolean;
};
That means TypeScript knows exactly which property names are valid.
The problem is that in your original code, name was typed as string:
interface trainInfo {
name: string;
}
When TypeScript sees this:
plotOptions[name]
it asks: "If can be string, how can I guarantee that property exists on ?"
Mental Model
Think of plotOptions like a locker cabinet with exactly four labeled doors:
train_1train_2train_3train_4
If someone gives you a key labeled just string, that is like saying:
"Here is a key for some door name."
TypeScript responds:
"I only know these four doors. If you cannot guarantee the label matches one of them, I will not let you open it."
But if the key is typed as:
"train_1" | "train_2" | "train_3" | "train_4"
then TypeScript knows the key fits one of the actual doors, so access is allowed.
A plain string is too vague. A keyof type is a verified label.
Syntax and Examples
Core syntax
Use keyof when a variable must match one of an object's keys.
type PlotOptions = {
train_1: boolean;
train_2: boolean;
train_3: boolean;
train_4: boolean;
};
type TrainName = keyof PlotOptions;
Now use that key type where needed:
interface TrainInfo {
name: TrainName;
}
const plotOptions: PlotOptions = {
train_1: true,
train_2: false,
train_3: true,
train_4: true
};
const item: TrainInfo = { name: "train_1" };
console.log(plotOptions[item.name]); // boolean
Step by Step Execution
Example to trace
type PlotOptions = {
train_1: boolean;
train_2: boolean;
train_3: boolean;
train_4: boolean;
};
type TrainName = keyof PlotOptions;
interface TrainInfo {
name: TrainName;
}
const plotOptions: PlotOptions = {
train_1: true,
train_2: false,
train_3: true,
train_4: true
};
const trains: TrainInfo[] = [
{ name: "train_1" },
{ name: "train_2" },
{ name: "train_3" }
];
const visible = trains.filter(({ name }) => plotOptions[name]);
What happens step by step
1. defines allowed keys
Real World Use Cases
This pattern appears often in TypeScript projects.
Feature flags
type FeatureFlags = {
search: boolean;
billing: boolean;
analytics: boolean;
};
A component may render sections based on keys like search or billing.
Form field visibility
type VisibleFields = {
email: boolean;
phone: boolean;
address: boolean;
};
A UI can show or hide fields by checking visible[fieldName].
API response mapping
You may group data under known keys and dynamically access a section only if the key is valid.
Chart configuration
Your example is a very common case: a config object stores whether each series should be shown, and the chart data array is filtered using the series name.
Permissions
= {
: ;
: ;
: ;
};
Real Codebase Usage
In real projects, developers usually avoid broad string types when the valid values are known.
Common pattern: derive keys from a config type
type PlotOptions = {
train_1: boolean;
train_2: boolean;
train_3: boolean;
train_4: boolean;
};
type TrainName = keyof PlotOptions;
This keeps key names in one place.
Pattern: reuse literal unions across state and data
interface TrainInfo {
name: TrainName;
}
This links your data model to your state model, reducing mismatches.
Pattern: guard clauses for unknown external values
If a key comes from user input or an API, it may truly be an arbitrary string. In that case, narrow it before indexing:
function isTrainName(value: string): value is TrainName {
value plotOptions;
}
keyFromApi = ;
((keyFromApi)) {
.(plotOptions[keyFromApi]);
}
Common Mistakes
1. Typing a known key as plain string
Broken
interface TrainInfo {
name: string;
}
Why it fails
string is too broad. TypeScript cannot guarantee that plotOptions[name] exists.
Fix
type TrainName = keyof PlotOptions;
interface TrainInfo {
name: TrainName;
}
2. Adding an index signature when keys are fixed
Overly broad
type PlotOptions = {
[key: string]: boolean;
train_1: boolean;
train_2: boolean;
train_3: boolean;
train_4: boolean;
};
Comparisons
Fixed keys vs index signature
| Approach | Example | Best for | Pros | Cons |
|---|---|---|---|---|
| Fixed object type | { train_1: boolean; train_2: boolean } | Known keys | Strong safety, catches typos | Less flexible |
| Index signature | { [key: string]: boolean } | Dynamic keys | Flexible | Allows too many keys |
Record<string, boolean> | Record<string, boolean> | Dynamic dictionaries | Short syntax | Same weakness as index signature |
keyof derived union |
Cheat Sheet
Quick fix
type PlotOptions = {
train_1: boolean;
train_2: boolean;
train_3: boolean;
train_4: boolean;
};
type TrainName = keyof PlotOptions;
interface TrainInfo {
name: TrainName;
}
Then this works:
plotOptions[name]
Rule to remember
If an object has specific keys, you cannot safely index it with a plain string.
Use:
keyof SomeType
when the variable should be one of that object's keys.
Common patterns
Safe object indexing
function getValue(obj: PlotOptions, key: keyof ) {
obj[key];
}
FAQ
Why does TypeScript say a string cannot be used to index an object?
Because a plain string could be any value, but your object only supports specific keys. TypeScript requires proof that the key is valid.
What does keyof do in TypeScript?
keyof creates a union of an object's property names. For example, keyof PlotOptions becomes "train_1" | "train_2" | "train_3" | "train_4".
Should I use an index signature to fix this error?
Only if your object truly supports arbitrary string keys. If the keys are known ahead of time, keyof is a better and safer solution.
Is plotOptions[name as keyof PlotOptions] a good fix?
It can work, but it is a fallback. It is better to type name correctly so the compiler can verify it naturally.
Why didn't my index signature solve the problem cleanly?
Because the real issue was that name was still typed too broadly. Also, an index signature may make the type less precise than your actual data.
How do I type React state for this case?
Keep the state shape simple and exact:
interface {
: ;
}
Mini Project
Description
Build a small TypeScript module for toggling which chart series are visible. This demonstrates safe object indexing with keyof, fixed object shapes, and filtering an array based on typed keys.
Goal
Create a typed chart-filtering utility where each series name must match a valid key in the visibility settings object.
Requirements
- Define a
PlotOptionstype with at least three fixed series keys. - Derive a key type from
PlotOptionsusingkeyof. - Create a
TrainInfoorSeriesInfotype whosenameproperty uses that key type. - Build an array of series objects and filter it based on the visibility settings.
- Print or return only the visible series.
Keep learning
Related questions
Angular formGroup Error Explained: Fixing 'Can't bind to formGroup' in Reactive Forms
Learn why Angular shows 'Can't bind to formGroup' and how to fix it by importing ReactiveFormsModule correctly.
Fix "Property has no initializer" in Angular TypeScript Components
Learn why Angular TypeScript shows "Property has no initializer" and how to fix it using defaults, optional properties, or definite assignment.
Fix 'Could not find a declaration file for module' in TypeScript
Learn why TypeScript cannot find declaration files for a package and how to fix it with types, package.json, and module resolution.