Как передать свойство объекта в качестве аргумента в TypeScript - PullRequest
0 голосов
/ 03 августа 2020

Я пытаюсь написать собственный перехватчик реакции, используя TypeScript. Я написал простую вспомогательную функцию, которая помогает мне проверить, есть ли такое свойство в целевом объекте:

export function hasOwnProperty<X extends {}, Y extends PropertyKey>(
  obj: X,
  prop: Y,
): obj is X & Record<Y, unknown> {
  return obj.hasOwnProperty(prop);
}

И я пытаюсь использовать его в своем хуке:

export const useAutocomplete = <T, Y extends PropertyKey>(data: Array<T>, property?: Y) => {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState<T[]>([]);

  const findResults = (element: T) => {
    if (property && hasOwnProperty(element, property)) {
      return String(element[property])
        .toLowerCase()
        .includes(query.toLowerCase());
    }
    return String(element).toLowerCase().includes(query.toLowerCase());
  };

  // ...other code

};

Проблема в том, что я не могу использовать такие методы, как toLowerCase() и другие, даже если я проверяю if (typeof obj[property] === 'string'), это не работает. Вот почему я решил обернуть свой объект в String, и тогда я смогу получить доступ к нужным мне методам. Но я думаю, что это не очень хорошее решение, и хочу спросить, как лучше понять это?

Ответы [ 2 ]

0 голосов
/ 10 августа 2020

Наконец я понял, как сделать его по-настоящему красивым и гибким! Вы можете оставлять свои комментарии, если есть способ сделать его более понятным, коротким и гибким. В своем решении я использовал перегрузку функций и частичный тип:

export const useAutocomplete = <T>(
  data: Array<T>,
  property?: Partial<T>,
) => {
  // Declaring state

  const [query, setQuery] = useState('');
  const [results, setResults] = useState<T[]>([]);

  // Creating type
  // for overloading function
  // it will allow us to accept
  // both simple string arrays
  // and sort by specific properties

  type Overloaded = {
    (element: string): boolean;
    (element: T): boolean;
  };

  // Simple helper function
  const getValue = (value: string, target: string) => value
    .toLowerCase()
    .includes(target.toLowerCase());

  // Getting keys
  const getObjectKeys = (
    criteria: Partial<Cocktail>,
  ) => Object.keys(criteria) as (keyof Cocktail)[];

  const findResults: Overloaded = (element: any) => {
    if (property) {
      const propertyValue = getObjectKeys(property);
      return propertyValue.every((value) => getValue(element[value], query));
    }
    return getValue(element, query);
  };

  const handleSearch = (e: React.SyntheticEvent) => {
    const target = e.target as HTMLInputElement;
    setQuery(target.value);
    const searchResults = data.filter(findResults);
    setResults(searchResults);
  };

  return { handleSearch, results, query };
};
0 голосов
/ 03 августа 2020

Машинопись не знает, что такое T

Явно сообщите машинописи, что ваш T является объектом со строковыми значениями

T extends { [key: string]: string}

полный код

export const useAutocomplete = <T extends { [key: string]: string }, Y extends PropertyKey>(data: Array<T>, property?: Y) => {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState<T[]>([]);

  const findResults = (element: T) => {
    if (property && hasOwnProperty(element, property)) {
      return element[property]
        .toLowerCase()
        .includes(query.toLowerCase());
    }
    return String(element).toLowerCase().includes(query.toLowerCase());
  };

  // ...other code

};
...