Ссылка на игровую площадку здесь
Я хочу определить функцию searchText
, которая принимает массив объектов, которые необходимо отфильтровать, массив свойств объектов, которые будут просматриваться, и строковое значение, которое будет искать. В конце я хочу, чтобы что-то подобное было возможно:
type User = { firstName: string, lastName: string, age: number}
let users: User[] = [
{ firstName: 'John', lastName: 'Smith', age: 22},
{ firstName: 'Ted', lastName: 'Johnson', age: 32}
]
searchText(users, ['firstName', 'lastName'], 'john') // should find both entries
Я хочу ограничить эту функцию, чтобы она принимала только допустимые массивы имен свойств. Допустимый массив должен содержать только те свойства, которые имеют тип строки, так как функция ищет текст. В другом вопросе SO я нашел способ определить тип, который должен позволять только допустимые значения ({ ссылка }). Этот тип определен как
type KeysMatching<T, V> = {[K in keyof T]: T[K] extends V ? K : never}[keyof T];
. С этим типом я могу определить функцию, которая позволяет указывать «допустимое ограничение массива»
function searchTextInUsers(users: User[], stringFields: KeysMatching<User, string>[], text: string): User[]{
return users.filter(user =>
stringFields.some(field => user[field].toLowerCase().includes(text.toLowerCase()))
);
}
Это компилируется и работает, как ожидается. Попытка передать не строковое свойство вызывает ошибку компиляции
searchTextInUsers(users, ['firstName', 'lastName', 'age'], 'john') // ERROR: Type 'string' is not assignable to type '"firstName" | "lastName"'.
Но на самом деле я хотел написать функцию, которая бы работала для любого типа, не только User
, но, что удивительно, просто добавив Параметр типа generi c не работает.
function searchText<T>(elements: T[], stringFields: KeysMatching<T, string>[], text: string): T[]{
return elements.filter(element =>
stringFields.some(field => element[field].toLowerCase().includes(text.toLowerCase())) // Error on this line
);
}
Компилятор показывает следующую ошибку
Свойство 'toLowerCase' не существует для типа 'T [{[K в keyof T]: T [K] расширяет строку? К: никогда; } [keyof T]] '
Может кто-нибудь объяснить, почему это не сработало и почему в этом случае машинопись не сужает тип до строки? Есть ли другой способ добиться того, что я хочу сделать при использовании типов generi c? Ссылка на игровую площадку здесь