如何在TypeScript中将对象属性作为参数传递

时间:2020-08-03 08:48:03

标签: typescript react-typescript

我正在尝试使用TypeScript编写自定义的React钩子。 我编写了简单的辅助函数,可以帮助我检查目标对象中是否存在这样的属性:

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 :(得分:0)

Typescript不知道什么是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

};

答案 1 :(得分:0)

最后,我弄清楚了如何使它真正变得美观而灵活! 您可以留下您的评论,如果有的话,可以使其更简洁,简短和灵活。 在我的解决方案中,我使用了函数重载和部分类型:

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 };
};