Capítulo 37 de 54
Fuzzy (approximate) filtering isn't a built-in feature — it's a recipe combining a custom filterFn built on @tanstack/match-sorter-utils' rankItem, filterMeta to carry the rank score, and a paired custom sortFn that reads that score, so results filter and sort by match quality.
@tanstack/match-sorter-utils, TanStack's fork of Kent C. Dodds' match-sorter, adapted for row-by-row filtering. Optional in principle — you could write ranking logic yourself — but this is the standard path.rankItem(row.getValue(columnId), value), stores the resulting RankingInfo via addMeta?.({ itemRank }) (optional-chained since addMeta may be undefined), and returns itemRank.passed.filterMeta slot (see Table and Column Meta Guide): declare interface FuzzyFilterMeta { itemRank?: RankingInfo }, build a FuzzyFeatures = TableFeatures & { filterMeta: FuzzyFilterMeta } type, annotate the filter function as FilterFn<FuzzyFeatures, RowData>, and register filterMeta: metaHelper<FuzzyFilterMeta>() alongside filterFns: { fuzzy: fuzzyFilter } in tableFeatures(). No global declare module augmentation needed — the slot is scoped to that one features object.rowA.columnFiltersMeta[columnId] (the meta stashed by the filter) and calls compareItems(rankA, rankB) from match-sorter-utils, falling back to sortFn_alphanumeric when ranks tie or no ranking info exists (e.g. sorting without an active filter). Register it as sortFns: { fuzzy: fuzzySort }.fuzzy name: as globalFilterFn: 'fuzzy' on the table for cross-column search, or as a per-column filterFn: 'fuzzy' (commonly paired with sortFn: 'fuzzy' on the same column) for one field — e.g. a computed fullName accessor column. Either can also skip registration and pass the function directly instead of a string.rowSortingFeature + sortedRowModel: createSortedRowModel() registered alongside filtering if you also want the sort-by-rank behavior.interface FuzzyFilterMeta { itemRank?: RankingInfo }
type FuzzyFeatures = TableFeatures & { filterMeta: FuzzyFilterMeta }
const fuzzyFilter: FilterFn<FuzzyFeatures, RowData> = (row, columnId, value, addMeta) => {
const itemRank = rankItem(row.getValue(columnId), value)
addMeta?.({ itemRank })
return itemRank.passed
}
const fuzzySort: SortFn<FuzzyFeatures, Person> = (rowA, rowB, columnId) => {
const a = rowA.columnFiltersMeta[columnId]
const dir = a ? compareItems(a.itemRank!, rowB.columnFiltersMeta[columnId]?.itemRank!) : 0
return dir === 0 ? sortFn_alphanumeric(rowA, rowB, columnId) : dir
}
const features = tableFeatures({
columnFilteringFeature, globalFilteringFeature, rowSortingFeature,
filteredRowModel: createFilteredRowModel(), sortedRowModel: createSortedRowModel(),
filterFns: { fuzzy: fuzzyFilter }, sortFns: { fuzzy: fuzzySort },
filterMeta: metaHelper<FuzzyFilterMeta>(),
})
const table = useTable({ features, columns, data, globalFilterFn: 'fuzzy' })
'fuzzy' name.filterFn, filterMeta, paired sortFn), not a separate feature to register.globalFilterFn for whole-table search, or per-column filterFn/sortFn for one field (e.g. a combined name column) — same registered function either way.filterMeta/metaHelper, the mechanism carrying rank data from filter to sort.globalFilterFn/filterFn get set.sortFn_alphanumeric and the general custom-sort-function shape.