Borislav Hadzhiev
Tue Mar 08 2022·3 min read
Photo by Kinga Cichewicz
The error "No index signature with a parameter of type 'string' was found on
type" occurs when we use a value of type string
to index an object with
specific keys. To solve the error, type the string
as one of the object's keys
using keyof typeof obj
.
Here is an example of how the error occurs.
const key = 'country' as string; const obj = { name: 'Tom', country: 'Germany', }; // ⛔️ Error: No index signature with a parameter of type // 'string' was found on type '{ name: string; country: string; }'.ts(7053) console.log(obj[key]);
The key
variable has a type of string
and this could be any string
.
We get the error when we try to access an object that has a name
and country
properties.
string
is too broad and not all strings are keys in the object, so we have to make sure the specific string is one of the object's keys.The first way to solve the error is to use a type assertion.
const key = 'country' as string; const obj = { name: 'Tom', country: 'Germany', }; // 👇️ "Germany" console.log(obj[key as keyof typeof obj]); // 👇️ type OnlyKeys = 'name' | 'country' type OnlyKeys = keyof typeof obj;
We used a type assertion to indicate to TypeScript that the key
variable is
not of type string
, but rather it is a union type containing only the keys of
the object.
Now TypeScript lets us access the specific property without throwing the error.
We used keyof typeof to get a union type of the object's keys.
If you are working with a type directly, you would just use keyof MyType
to
get a union of the object's keys.
interface Employee { name: string; country: string; } const obj: Employee = { name: 'Tom', country: 'Germany', }; const key = 'country' as string; // 👇️ "Germany" console.log(obj[key as keyof Employee]); // 👇️ type OnlyKeys = 'name' | 'country' type OnlyKeys = keyof Employee;
Notice that we used keyof Employee
and not keyof typeof Employee
, because
Employee
is a type, and not an object.
An even better way to solve this issue is to type the key
variable as
keyof Employee
to indicate to TypeScript that the string
will only ever be
one of the object's keys.
interface Employee { name: string; country: string; } const obj: Employee = { name: 'Tom', country: 'Germany', }; // 👇️ key can only be one of the object's keys const key: keyof Employee = 'country'; // 👇️ "Germany" console.log(obj[key as keyof Employee]);
Now we don't have to use any type assertions, which is much better.
Type assertions are used when we have information about the type of a value that TypeScript can't know about.
X
will be of type Y
and not to worry about it. This could cause runtime errors if we are wrong.Here is another example of how you could type a value to only be one of the object's keys.
interface Employee { name: string; country: string; } const obj1: Employee = { name: 'Tom', country: 'Germany', }; interface AccessEmployee { keyName: keyof Employee; // 👈️ one of Employee's keys } const obj2: AccessEmployee = { keyName: 'country', }; // 👇️ "Germany" console.log(obj1[obj2.keyName]);
We are using the obj2.keyName
property to access a property in obj1
.
To be able to do this, we had to type the keyName
property in obj2
to be of
type keyof Employee
.
The keyName
property in obj2
can only ever have a value of name
or
country
, so TypeScript allows us to safely access the specific properties in
obj1
.
This is the most type safe solution to the error, because if we ever try to
change the value of obj2.keyName
to an incompatible type, we'd get an error.
interface Employee { name: string; country: string; } interface AccessEmployee { keyName: keyof Employee; // 👈️ one of Employee's keys } const obj2: AccessEmployee = { keyName: 'country', }; // ⛔️ Type '"something else"' is not assignable // to type 'keyof Employee'.ts(2322) obj2.keyName = 'something else';
Trying to set obj2.keyName
to any other value than name
or country
causes
the type checker to issue an error.