Определение типа для свойств объекта, которые являются строками. Различия между generi c и явными типами - PullRequest
0 голосов
/ 02 мая 2020

Ссылка на игровую площадку здесь

Я хочу определить функцию 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? Ссылка на игровую площадку здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...