Skip to content

Custom Sort Functions

The Sort module allows you to extend sorting with custom compare functions. Compare functions take two values of the same type and return a number following the Array.prototype.sort comparator contract.

Use defineTypedFn to create a type-safe compare function:

import { z } from "zod";
import { defineTypedFn, createSorterSphere } from "@fn-sphere/core";
const numberCompare = defineTypedFn({
name: "number compare",
define: z.function({
input: [z.number(), z.number()],
output: z.number(),
}),
implement: (a, b) => a - b,
});
  • name: A unique string identifying your compare function.
  • define: A Zod function schema with exactly 2 parameters of the same type, returning a number.
  • implement: The comparator logic. Return negative if a < b, positive if a > b, and 0 if equal.

Pass your custom functions to createSorterSphere:

import { createSorterSphere, presetSort } from "@fn-sphere/core";
const sphere = createSorterSphere(schema, [
numberCompare,
...presetSort, // Include preset sort functions if needed
]);

Generic compare functions work across multiple data types. Use defineGenericFn to create one:

import { z } from "zod";
import { defineGenericFn } from "@fn-sphere/core";
import type { $ZodString, $ZodNumber } from "zod/v4/core";
const caseInsensitiveSort = defineGenericFn({
name: "case insensitive sort",
genericLimit: (t): t is $ZodString => t._zod.def.type === "string",
define: (t) =>
z.function({
input: [t, t],
output: z.number(),
}),
implement: (a: string, b: string) =>
a.toLowerCase().localeCompare(b.toLowerCase()),
});

Key properties:

  • name: A unique string identifying your compare function.
  • genericLimit: A type guard that determines which Zod types this function applies to.
  • define: A function that receives the matched type and returns a Zod function schema.
  • implement: The comparator logic that handles all specified types.

The sort module supports sorting by multiple fields with cascading priority. The first non-zero comparison result wins:

1.
2.
departmentnameagescore
DesignCharlie3572
DesignDiana2891
DesignHenry4067
EngineeringAlice3088
EngineeringBob2595
EngineeringEve3285
MarketingFrank2278
MarketingGrace2793
const sphere = createSorterSphere(schema, presetSort);
const fields = sphere.findSortableField();
const nameField = fields.find((f) => f.path[0] === "name")!;
const ageField = fields.find((f) => f.path[0] === "age")!;
// Sort by name ascending, then by age descending
const rule = [
sphere.getSortRule(nameField, nameField.sortFnList[0]!, "asc"),
sphere.getSortRule(ageField, ageField.sortFnList[0]!, "desc"),
];
const sorted = sphere.sortData(users, rule);