Borislav Hadzhiev
Fri Mar 18 2022·3 min read
Photo by Cody Black
The error "No index signature with a parameter of type 'string' was found on
type" occurs when a string
is used, but a more specific string literal is
expected. To solve the error, use the keyof
operator to cast the string to the
correct type, e.g. employee[str as keyof Employee]
.
Here is an example of how the error occurs.
type Employee = { id: number; name: string; salary: number; }; const employee: Employee = { id: 1, name: 'Alice', salary: 100, }; function example(str: string) { // ⛔️ Error: No index signature with a parameter // of type 'string' was found on type 'Employee'.ts(7053) return employee[str]; }
The employee
object can only be indexed with very specific string literals -
id
, name
and salary
, but we are trying to index it with any string
value, which causes the error.
To solve the error, use the keyof
operator to cast the string to one of the
keys in the type.
type Employee = { id: number; name: string; salary: number; }; const employee: Employee = { id: 1, name: 'Alice', salary: 100, }; function example(str: string) { // ✅ Works now return employee[str as keyof Employee]; }
We used a
type assertion
to cast the str
parameter as one of the keys in the Employee
type.
If you need to get a type of the object's keys, use keyof typeof
instead.
type Employee = { id: number; name: string; salary: number; }; const employee: Employee = { id: 1, name: 'Alice', salary: 100, }; function example(str: string) { return employee[str as keyof typeof employee]; }
We used keyof typeof
, because employee
is an object and not a type.
type Employee = { id: number; name: string; salary: number; }; const employee: Employee = { id: 1, name: 'Alice', salary: 100, }; // 👇️ type T1 = 'id' | 'name' | 'salary' type T1 = keyof typeof employee; // 👇️ type T2 = 'id' | 'name' | 'salary' type T2 = keyof Employee;
The snippet illustrates how to get a type that consists of the keys of a type alias or the keys of an object.
A much better solution in this case would be to type the function parameter to be one of the keys of the type alias.
type Employee = { id: number; name: string; salary: number; }; const employee: Employee = { id: 1, name: 'Alice', salary: 100, }; // 👇️ correctly typed str param function example(str: keyof Employee) { return employee[str]; } console.log(example('name')); // 👉️ 'Alice' console.log(example('id')); // 👉️ 1 // ⛔️ Error: Argument of type '"test"' is // not assignable to parameter of type 'keyof Employee'.ts(2345) console.log(example('test'));
str
parameters to be one of the keys in the Employee
type. This is much better because we get type checking and autocompletion when passing parameters to the function.Alternatively, you can use a type predicate to determine if the string
is one
of the keys in the specific type.
type Employee = { id: number; name: string; salary: number; }; const employee: Employee = { id: 1, name: 'Alice', salary: 100, }; function isAnEmployeeProperty(str: string): str is keyof Employee { return ['id', 'name', 'salary'].includes(str); } const myIdentifier = 'name' as string; if (isAnEmployeeProperty(myIdentifier)) { console.log(employee[myIdentifier]); // 👉️ "Alice" }
The str is keyof Employee
syntax is a
type predicate.
parameter is Type
, where parameter
is the name of a parameter from the function signature.This allows TypeScript to narrow down the variable to a specific type if it is compatible to the original type.
In the isAnEmployeeProperty
function, we simply check if the passed in string
is one of the object's keys and return the result.
If we enter the if
block, TypeScript knows that the myIdentifier
variable is
one of the keys in the object and allows us to use it to index the object.
Which approach you pick is a matter of personal preference. The type predicate approach provides better type safety than a type assertion, but is a bit more verbose and more difficult to read at first.