Skip to content

feat: expose rank info in results#169

Merged
kentcdodds merged 1 commit into
kentcdodds:mainfrom
justinwaite:jdw/ranked-metadata
Apr 15, 2026
Merged

feat: expose rank info in results#169
kentcdodds merged 1 commit into
kentcdodds:mainfrom
justinwaite:jdw/ranked-metadata

Conversation

@justinwaite

@justinwaite justinwaite commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

What:

Allow callers to opt into match metadata so they can use ranking details without reimplementing the sorter.

Why:

For cases when you want to use matchSort but need to save/extract information about how each item was ranked after matchSort runs.

How:

Added a new option called returnRankInfo and an overload for matchSorter. When returnRankInfo is true, the return type is {item: T, ...rankInfo}[] but when false it is still just T[]

Checklist:

  • Documentation
  • Tests
  • Ready to be merged

Summary by CodeRabbit

  • New Features

    • Added a new function that returns matched items with ranking metadata (item, rankedValue, rank, keyIndex, keyThreshold, index).
  • Documentation

    • README updated with usage examples showing the new ranked-item output and improved code formatting in examples.
  • Tests

    • Added tests verifying the ranked-item output structure, ordering, and behavior both with and without options.
  • Refactor

    • Core matching now centralizes ranking so existing match results continue to work while enabling the new ranked-output function.

@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6debacd3-589b-4ac4-ab18-2134a506d1c8

📥 Commits

Reviewing files that changed from the base of the PR and between 82dac06 and 289ffc0.

📒 Files selected for processing (3)
  • README.md
  • src/__tests__/index.ts
  • src/index.ts
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/tests/index.ts
  • src/index.ts

📝 Walkthrough

Walkthrough

Adds a new exported function matchSorterWithRankInfo and exported RankedItem type that return full ranking metadata; refactors matchSorter to reuse a shared helper getRankedItems (which produces ranked objects) and map its results to items; updates README and tests to demonstrate and validate the new API.

Changes

Cohort / File(s) Summary
Documentation
README.md
Added usage examples for matchSorterWithRankInfo(list, value) and showed structure of returned ranking metadata objects; minor formatting/whitespace tweaks in example code.
Core implementation
src/index.ts
Introduced getRankedItems helper, added and exported matchSorterWithRankInfo and export type RankedItem<...>, refactored matchSorter to call getRankedItems and map to items, and attached rankings to the new function.
Tests
src/__tests__/index.ts
Imported matchSorterWithRankInfo and type RankedItem; added tests asserting returned ranked objects include item, rankedValue, rank, keyIndex, keyThreshold, and index, and that function works without options.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Suggested reviewers

  • kentcdodds

Poem

🐰 I hopped through code and tests with glee,
I carried ranks and keys for all to see,
Now items come with metadata bright,
A little hop, and sorting's right —
🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: exposing ranking metadata in matchSorter results through a new matchSorterWithRankInfo function and RankedItem type export.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/index.ts (1)

50-62: ⚠️ Potential issue | 🟠 Major

Overload typing is unsound when returnRankInfo is a non-literal boolean.

When returnRankInfo is a variable of type boolean (not a literal true or false), TypeScript selects the second overload (line 93–97) and types the return as Array<ItemType>. However, the runtime can return Array<RankedItem<ItemType>> if that variable evaluates to true at runtime, creating a type safety gap.

To fix, change returnRankInfo?: boolean to returnRankInfo?: false in MatchSorterOptions. This forces narrowing of non-literal booleans and ensures overload selection aligns with runtime behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/index.ts` around lines 50 - 62, The overload is unsound because
MatchSorterOptions currently declares returnRankInfo?: boolean; change that to
returnRankInfo?: false so non-literal booleans are not treated as the
true-specialized overload; update the interface definition for
MatchSorterOptions (and keep MatchSorterRankInfoOptions with returnRankInfo:
true) so TypeScript will narrow correctly and the overload resolution for
functions that use MatchSorterOptions/MatchSorterRankInfoOptions matches runtime
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/index.ts`:
- Around line 50-62: The overload is unsound because MatchSorterOptions
currently declares returnRankInfo?: boolean; change that to returnRankInfo?:
false so non-literal booleans are not treated as the true-specialized overload;
update the interface definition for MatchSorterOptions (and keep
MatchSorterRankInfoOptions with returnRankInfo: true) so TypeScript will narrow
correctly and the overload resolution for functions that use
MatchSorterOptions/MatchSorterRankInfoOptions matches runtime behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 20c5038d-e245-4440-b7de-4311ec7e598d

📥 Commits

Reviewing files that changed from the base of the PR and between 6be7acb and 06b74f0.

📒 Files selected for processing (3)
  • README.md
  • src/__tests__/index.ts
  • src/index.ts

@kentcdodds kentcdodds left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this! I think it's useful. Just some notes on types.

Comment thread src/index.ts Outdated
value: string,
options: MatchSorterOptions<ItemType> = {},
): Array<ItemType> {
): Array<ItemType> | Array<RankedItem<ItemType>> {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's some clever TypeScript schenanigans you can do here to make sure the type is only Array<RankedItem<ItemType>> if options.returnRankInfo === true. Could you do that?

Either that, or let's make a new matchSorterWithRankInfo method to keep things tidy with types.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey kent,

that is the job of the function overloading in the top, and seems to be working as intended for me:

Screen.Recording.2026-04-14.at.6.42.33.PM.mov

but i'm also down to expose a separate function if that would feel safer

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also works if the property isn't provided at all:

Screen.Recording.2026-04-14.at.6.43.44.PM.mov

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to coderabbit's point, if it's not a literal, it just defaults to T[] which could be misleading.

@justinwaite justinwaite Apr 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

k pushed a fix and now the types behave as you would expect:

For literal true: RankedItem[]
For literal false/undefined (existing usages): T[]
For a boolean value: RankedItem[] | T[] (rare case)

Screen.Recording.2026-04-14.at.6.52.37.PM.mov

This could still technically break someone's existing types.

If a consumer had a function that was wrapping up the matchSorter types, and were doing passthrough options like this:

// this would now return `T[] | RankedItem<T>[]` which would be a type-breaking change
function myWrapper<T>({items, query, options}: {
  items: T,
  query: string,
  options: Parameters<typeof matchSorter<T>>[2],
}) {
  return matchSorter(items, query, options);
}

this would now return T[] | RankedItem<T>[] instead of just T[] and would break their typechecks.

However, if the consumer was using the proper MatchSorterOptions<T> type, they would be unaffected:

// this continue to work fine, with typescript declaring T[] as the return type
function myWrapper<T>({items, query, options}: {
  items: T,
  query: string,
  options: MatchSorterOptions<T>
}) {
  return matchSorter(items, query, options);
}

So your call, @kentcdodds, on whether you think this would be a problem. Options are:

  • keep the function overloading as working now in the PR with slight risk of breaking someone's types if they weren't using the MatchSorterOptions and were instead inferring types of the parameters and passing along. I think this would be a pretty rare case.
  • move to separate functions entirely which would obviously eliminate the type problem altogether. but now you have two functions to export, and two is more than one.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking at that. Let's just do two functions

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kentcdodds it is done, i've split them into separate functions while share core logic. lmk what you think

@justinwaite justinwaite force-pushed the jdw/ranked-metadata branch from 82dac06 to 289ffc0 Compare April 15, 2026 05:11

@kentcdodds kentcdodds left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent! Thanks!

@kentcdodds kentcdodds merged commit e7c9c20 into kentcdodds:main Apr 15, 2026
5 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 8.3.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants