krisk / Fuse

Lightweight fuzzy-search, in JavaScript
https://fusejs.io/
Apache License 2.0
18.1k stars 766 forks source link

Type 'string' is not assignable to type '{ name: never; weight: number; }'. #274

Closed Thomas0921 closed 4 years ago

Thomas0921 commented 5 years ago

I get this error every time I test my app. Could you identify this error and solution?

Argument of type '{ shouldSort: boolean; threshold: number; location: number; distance: number; 
maxPatternLength: n...' is not assignable to parameter of type 'FuseOptions<{}>'. Types of property 
'keys' are incompatible. Type 'string[]' is not assignable to type 'never[] | { name: never; weight: 
number; }[]'. Type 'string[]' is not assignable to type '{ name: never; weight: number; }[]'. Type 'string' is 
not assignable to type '{ name: never; weight: number; }'.

The error occur on this line

const fuse = new Fuse(this.searchList, options)

in my line, this search is put in a function, that I will call it whenever I key anything in my input

 filterQuery(val) {
 const options = {
  shouldSort: true,
  threshold: 0.4,
  location: 0,
  distance: 100,
  maxPatternLength: 16,
  minMatchCharLength: 1,
  keys: ["name"]
};

const fuse = new Fuse(this.searchList, options)

const results = this.sortList(fuse.search(val));
const newResult = [];

for (let i = 0; i < results.length; i++) {
  newResult.push(results[i]);
  if (i > 6) break;
}
this.filteredList = newResult;
}
krisk commented 5 years ago

What does searchList look like?

vidit-sh commented 5 years ago

I get similar error.

const items = [
  {
    id: 1,
    name: 'abc',
    quantity: 500,
    unit: 'kg',
    group: 0,
    subgroup: 0,
  },
];

  const options = {
    keys: ['name'],
  };
  const fuse = new Fuse(items, options);
  const result = fuse.search('');

It shows me following error.

Argument of type '{ keys: string[]; }' is not assignable to parameter of type 'FuseOptions<{ id: number; name: string; quantity: number; unit: string; group: number; subgroup: number; }>'.
  Types of property 'keys' are incompatible.
    Type 'string[]' is not assignable to type '("name" | "id" | "quantity" | "unit" | "group" | "subgroup")[] | { name: "name" | "id" | "quantity" | "unit" | "group" | "subgroup"; weight: number; }[] | undefined'.
      Type 'string[]' is not assignable to type '("name" | "id" | "quantity" | "unit" | "group" | "subgroup")[]'.
        Type 'string' is not assignable to type '"name" | "id" | "quantity" | "unit" | "group" | "subgroup"'.ts(2345)
mithunm93 commented 5 years ago

What I did was define a type for the items I'm passing in, and set that as the type of FuseOptions, and I was good.

interface ItemInterface {
  name: string
}

const items: ItemInterface[] = [{ name: "Mithun" }, ...];

const options: FuseOptions<ItemInterface> = {
  keys: ["name"],
};

const fuse = new Fuse(items, options);
favna commented 5 years ago

This issue can be closed.

The solution above is the correct solution going forward and will allow for strong typechecking throughout the code. The website has been updated with a TypeScript example a couple of days ago by yours truly.

Please note that Fuse makes use of generic types which ultimately allows us to take typings all the way down the chain. Your TSC will for example know that the result returned by .search will be an array of the type given at options and this also offers perfect IDE IntelliSense support.

bkonkle commented 5 years ago

Any idea on how to handle dot-access syntax for nested keys? Right now I'm having to @ts-ignore things:

    const matched = search
      ? getSuggestionsFromKeys(
        caregivers,
        // @ts-ignore - type limitation on dot-access syntax for nested keys
        ['attributes.displayName', 'attributes.headline']
      )
      : caregivers

Otherwise, it leads to the same Type 'string' is not assignable to type issue as above.

Edit: I'm realizing you need my actual usage, not just where I'm calling my abstracted function:

import Fuse, {FuseOptions} from 'fuse.js'

/**
 * Use the fuse.js library to implement fuzzy search
 */
export function getSuggestionsFromKeys<Item> (
  items: Item[],
  keys: FuseOptions<Item>['keys'],
  value?: string
) {
  const fuse = new Fuse(items, {
    shouldSort: true,
    threshold: 0.4,
    location: 0,
    distance: 100,
    maxPatternLength: 32,
    minMatchCharLength: 2,
    keys
  })

  const search = (query: string) => fuse.search(query.trim().toLowerCase())

  // Curry the function if the value was not provided
  if (value) {
    return search(value)
  } else {
    return search
  }
}
favna commented 5 years ago

@bkonkle as said in the comment right above yours please check the website on how to properly use Fuse.JS with TypeScript.

You need to split off the options to a separate constant and assign it the type of Fuse.FuseOptions where T is a Generic Type that describes the list your searchinf

github-actions[bot] commented 4 years ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days