TypeScript error "Argument of type 'string' is not assignable to parameter of type 'never'" when filtering array in React

3 days ago 10
ARTICLE AD BOX

I'm building a data filtering component in React/TypeScript, and I'm getting a confusing TypeScript error when trying to filter an array based on user input. The error says my string argument is type never, which doesn't make sense to me.

The Error

Argument of type 'string' is not assignable to parameter of type 'never'

Code Example

typescript

import { useState } from 'react'; interface User { id: number; name: string; email: string; role: 'admin' | 'user' | 'guest'; } export default function UserFilter() { const [users] = useState<User[]>([ { id: 1, name: 'Alice', email: '[email protected]', role: 'admin' }, { id: 2, name: 'Bob', email: '[email protected]', role: 'user' }, { id: 3, name: 'Charlie', email: '[email protected]', role: 'guest' }, ]); const [searchTerm, setSearchTerm] = useState(''); const [filterField, setFilterField] = useState('name'); // This is where the error occurs const filteredUsers = users.filter((user) => { return user[filterField].toLowerCase().includes(searchTerm.toLowerCase()); // ^^^^^^^^^^^^ // Error: Argument of type 'string' is not assignable to parameter of type 'never' }); return ( <div> <select value={filterField} onChange={(e) => setFilterField(e.target.value)}> <option value="name">Name</option> <option value="email">Email</option> <option value="role">Role</option> </select> <input type="text" value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} placeholder="Search..." /> <ul> {filteredUsers.map((user) => ( <li key={user.id}> {user.name} - {user.email} - {user.role} </li> ))} </ul> </div> ); }

Expected Behavior

I expect to:

Select a field to filter by (name, email, or role)

Type in the search box

See filtered users based on the selected field

Actual Behavior

TypeScript throws a compile error on user[filterField]:

Says filterField is type never

Won't let me access the user property dynamically

The code logically should work, but TypeScript won't compile it

What I've Tried

1. Using any type:

typescript

const filteredUsers = users.filter((user: any) => { return user[filterField].toLowerCase().includes(searchTerm.toLowerCase()); });

Result: Works but defeats the purpose of TypeScript

2. Type assertion:

typescript

return (user as any)[filterField].toLowerCase().includes(searchTerm.toLowerCase());

Result: Works but feels like a hack

3. Hardcoding the field:

typescript

return user.name.toLowerCase().includes(searchTerm.toLowerCase());

Result: Works but not dynamic - defeats the purpose

Questions

Why is TypeScript treating filterField as type never when it's clearly a string?

What's the correct way to dynamically access object properties in TypeScript when the property name comes from a variable?

How do I properly type filterField so TypeScript knows it's one of the valid User keys ('name' | 'email' | 'role')?

What I Think the Problem Is

I believe TypeScript doesn't know that filterField will always be one of the valid keys of User. It's treating it as any random string, which could try to access a property that doesn't exist.

But I'm not sure how to tell TypeScript: "This string will only ever be 'name', 'email', or 'role'".

Environment

React 18.2

TypeScript 5.0

Using strict mode in tsconfig.json

Research Done

I've read about:

TypeScript index signatures

keyof type operator

Type assertions

String literal types

But I'm confused about how to apply these concepts to solve this specific problem with dynamic property access in a React component.

Any help understanding the TypeScript error and the correct solution would be greatly appreciated!

Read Entire Article