Repository navigation
feat(types): add seven compile-time type utilities - #2044
Merged
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
dayongkr
force-pushed
the
feat/types-utilities
branch
from
August 20, 2026 11:02
f8ba8ac to
83d4334
Compare
dayongkr
force-pushed
the
feat/types-utilities
branch
from
August 26, 2026 11:02
4df63f9 to
83d4334
Compare
Adds IsEqual, Primitive, JsonValue, UnknownRecord, EmptyObject, SetOptional, and SetRequired, with reference pages in all four languages. IsEqual compares two types exactly. Unlike `A extends B`, which asks whether one fits into the other, it tells `any` apart from every other type, so it catches an accidental `any` in type-level tests. The same trick already exists in compat/_internal, which is left untouched here. Primitive covers the seven primitive values in the ECMAScript spec. Written by hand, this union usually misses bigint or symbol. JsonValue follows RFC 8259 and is recursive, so functions, Date, and undefined are excluded. It ships as one self-contained type rather than a JsonObject / JsonArray / JsonPrimitive family, since each of those is a one-liner at the call site. UnknownRecord and EmptyObject both build on Record<PropertyKey, ...>, one for "any object" and one for "no properties at all". EmptyObject pairs with the existing isEmptyObject guard. Only types with an index signature are assignable to UnknownRecord, which the docs call out along with the workarounds. SetOptional and SetRequired scope Partial and Required to specific keys. Both survive a union, so each member can still be told apart afterwards, and the specs pin that down. SetOptional needs a conditional type for it because Omit collapses a union to its shared keys; SetRequired does not, because an intersection leaves the union alone. Merge and ObjectKeys were exported and documented but missing from the intro table, so they are listed there as well.
dayongkr
force-pushed
the
feat/types-utilities
branch
from
August 26, 2026 11:27
2f1a738 to
f4e0879
Compare
The types were listed flat in the reference sidebar. They are now split into objects, values, and predicate through the categories field in flavors.mts, the same mechanism es-toolkit/compat already uses. The split is by what a type takes rather than what it does to it, so the key conversion types sit with the other object types: they all take an object. Values covers the types that define a set of values instead of transforming one, and predicate covers the types that resolve to true or false. Category labels can now be scoped per flavor. buildFlavorSidebar looks up `<flavor>:<category>` before falling back to the shared key, so es-toolkit/types can label its own predicate group without disturbing the runtime one, which means something different. Reference pages move into matching folders, so their URLs gain the category segment. Links in the intro, the relative links inside the moved pages, and the links coming in from the runtime function docs are all updated. The translated pages read as translations of the English ones in places, so the wording is reworked to match how each language actually reads. Notes that were filed under the type parameter heading move to their own section, since they are not parameters.
The omitBy and pickBy pages link to ObjectKeys with an absolute path, which the earlier pass missed because it only looked at relative markdown links. VitePress resolves these as routes at build time, so they failed the dead link check.
gwennlbh
pushed a commit
to cigaleapp/cigale
that referenced
this pull request
Sep 8, 2026
##### [v1.52.0](https://github.com/toss/es-toolkit/blob/HEAD/CHANGELOG.md#Version-v1520) Released on August 28th, 2026. - Added the `es-toolkit/iterator` entrypoint, a lazy iterator module with `chunk`, `count`, `dropWhile`, `head`, `iterate`, `partition`, `range`, `scan`, `takeWhile`, `uniqBy`, and `zip` (\[[#1815](toss/es-toolkit#1815)]), plus `cartesianProduct` (\[[#2031](toss/es-toolkit#2031)]). The same functions are also available from `es-toolkit/fp/iterator`. - Added `defer` and `deferAsync` to `es-toolkit/util`. (\[[#2032](toss/es-toolkit#2032)]) - Added `flowAsync` to `es-toolkit/fp`, a promise-aware left-to-right composition. (\[[#2033](toss/es-toolkit#2033)]) - Added the `EmptyObject`, `IsEqual`, `JSONValue`, `Primitive`, `SetOptional`, `SetRequired`, and `UnknownRecord` types. (\[[#2044](toss/es-toolkit#2044)]) - Fixed `merge` to infer the deep merged return type, and exported the `Merge` type. (\[[#1959](toss/es-toolkit#1959)]) - Fixed `omitBy` and `pickBy` to type numeric callback keys as strings, and exported the `ObjectKeys` type. (\[[#2037](toss/es-toolkit#2037)]) - Fixed `attempt` and `attemptAsync` to default their error type parameter to `unknown`. (\[[#2052](toss/es-toolkit#2052)]) The following bring `es-toolkit/compat` closer to Lodash. Behavior for the affected edge cases now matches Lodash, so results may differ if you relied on the previous output. - Fixed `compat/debounce` to skip the `maxWait` invocation when both `leading` and `trailing` are `false`. (\[[#1678](toss/es-toolkit#1678)]) - Fixed `compat/toString` to convert objects with a custom `valueOf`. (\[[#2034](toss/es-toolkit#2034)]) - Fixed `compat/mergeWith` to assign `null` values in array sources. (\[[#1929](toss/es-toolkit#1929)]) - Fixed `compat/has` and `compat/hasIn` to normalize the `-0` path key. (\[[#2035](toss/es-toolkit#2035)]) - Fixed `compat/differenceWith` and `compat/without` to normalize `-0` to `0`. (\[[#2049](toss/es-toolkit#2049)]) - Fixed `compat/findLastIndex` to convert `fromIndex` to an integer. (\[[#2047](toss/es-toolkit#2047)]) - Fixed `compat/xorWith` to match Lodash when no comparator is given. (\[[#2057](toss/es-toolkit#2057)]) - Covered the new iterator entrypoints in the dist and browser compatibility checks. (\[[#2030](toss/es-toolkit#2030)]) - Made the agent skills portable when installed on their own. (\[[#2054](toss/es-toolkit#2054)]) - Fixed documentation typos and the Deno install commands. (\[[#2062](toss/es-toolkit#2062)]) ##### [v1.51.0](https://github.com/toss/es-toolkit/blob/HEAD/CHANGELOG.md#Version-v1510) Released on August 17th, 2026. - Added the `es-toolkit/bigint` entrypoint: `bigint` counterparts of the math functions (`sum`, `sumBy`, `max`, `min`, `maxBy`, `minBy`, `clamp`, `inRange`, `median`, `medianBy`, `percentile`, `range`, `rangeRight`), kept separate so the `number` implementations stay unchanged. (\[[#1966](toss/es-toolkit#1966)]) - Added `dedent`, which removes common leading whitespace from template strings. (\[[#1679](toss/es-toolkit#1679)]) - Added `deepFreeze` for recursively freezing objects. (\[[#1680](toss/es-toolkit#1680)]) - Added `mapValuesAsync` and `mapKeysAsync`. (\[[#1544](toss/es-toolkit#1544)]) - Added `toPascalCaseKeys`, `toKebabCaseKeys`, and `toConstantCaseKeys`, completing the object key casing family. (\[[#1984](toss/es-toolkit#1984)]) - Exported the `ToCamelCaseKeys`, `ToPascalCaseKeys`, `ToSnakeCaseKeys`, `ToKebabCaseKeys`, and `ToConstantCaseKeys` types. (\[[#1651](toss/es-toolkit#1651)]) - Added a `preserveArrays` option to `flattenObject`. (\[[#974](toss/es-toolkit#974)]) - Fixed `retry` to pass the last error to the `delay` callback (\[[#1759](toss/es-toolkit#1759)]) and to throw the last attempt's error without applying a final delay (\[[#1901](toss/es-toolkit#1901)]). - Fixed `mergeWith` and `toMerged` to handle mixed array/object types consistently with `merge`. (\[[#2026](toss/es-toolkit#2026)]) - Fixed `pullAt` to remove the correct elements with negative indices. (\[[#1613](toss/es-toolkit#1613)]) - Fixed `at`, `pullAt`, `orderBy`, and `sortBy` to accept readonly arrays. (\[[#2016](toss/es-toolkit#2016)]) - Moved `limitAsync` from the array to the promise category. (\[[#2022](toss/es-toolkit#2022)]) - Included the NOTICE file in the published npm and JSR packages. (\[[#2020](toss/es-toolkit#2020)]) The following bring `es-toolkit/compat` closer to Lodash. Behavior for the affected edge cases now matches Lodash, so results may differ if you relied on the previous output. - Added `entries` and `entriesIn`. (\[[#1874](toss/es-toolkit#1874)]) - Fixed `compat/isMatch` and `compat/isMatchWith` to handle object source patterns against primitive and non-plain-object targets like Lodash. (\[[#1432](toss/es-toolkit#1432)]) - Fixed `compat/set` to block `constructor.prototype` paths, preventing prototype pollution. (\[[#1904](toss/es-toolkit#1904)]) - Fixed `compat/find` to respect array-like `length` (\[[#1958](toss/es-toolkit#1958)]) and to convert `fromIndex` to an integer (\[[#1961](toss/es-toolkit#1961)]), and `compat/indexOf` to convert `fromIndex` to an integer when searching for `NaN` (\[[#1951](toss/es-toolkit#1951)]). - Fixed `compat/orderBy` to resolve unresolved deep paths and nullish elements to `undefined` (\[[#2010](toss/es-toolkit#2010)]), to exclude the `length` property from array-like values (\[[#2002](toss/es-toolkit#2002)]), and to read the criterion property from primitive values (\[[#1903](toss/es-toolkit#1903)]). - Fixed `compat/toPath` to split unquoted dotted keys inside brackets. (\[[#1899](toss/es-toolkit#1899)]) - Fixed `compat/omit` to treat a key array as a single deep path. (\[[#1902](toss/es-toolkit#1902)]) - Fixed `compat/map` to make the iteratee optional with an identity default. (\[[#1928](toss/es-toolkit#1928)]) - Fixed `compat/size` to count combined Unicode symbols as single characters. (\[[#1900](toss/es-toolkit#1900)]) - Fixed `compat/intersectionBy` to support number, object, and nullish iteratee shorthands (\[[#1993](toss/es-toolkit#1993)]), and `compat/intersectionWith` to apply the comparator when deduplicating the first array (\[[#1953](toss/es-toolkit#1953)]). - Fixed `compat/difference`, `compat/differenceBy`, `compat/uniqBy`, and `compat/unionBy` to normalize `-0` to `0`. (\[[#2007](toss/es-toolkit#2007)]) - Fixed `compat/maxBy` and `compat/minBy` to skip nullish iteratee values (\[[#1927](toss/es-toolkit#1927)]), and `compat/meanBy` to skip `undefined` values when averaging (\[[#1978](toss/es-toolkit#1978)]). - Fixed `compat/some`, `compat/template` (\[[#2009](toss/es-toolkit#2009)]), and `compat/fill` (\[[#1952](toss/es-toolkit#1952)]) to gate guard handling with `isIterateeCall`. - Fixed `compat/iteratee` to treat a boolean as a property shorthand. (\[[#1941](toss/es-toolkit#1941)]) - Fixed `compat/reverse` to support array-like objects and `arguments`. (\[[#2008](toss/es-toolkit#2008)]) - Fixed `compat/toArray` to convert non-array-like iterables. (\[[#1999](toss/es-toolkit#1999)]) - Fixed `compat/toString` to render nested nullish values like Lodash. (\[[#1992](toss/es-toolkit#1992)]) - Fixed `compat/zipObject` to treat `null` keys and values as empty arrays. (\[[#2005](toss/es-toolkit#2005)]) - Fixed `compat/sampleSize` to clamp the default size to the collection length. (\[[#2003](toss/es-toolkit#2003)]) - Fixed `compat/takeWhile`, `compat/takeRightWhile`, and `compat/uniqBy` to support string inputs. (\[[#2004](toss/es-toolkit#2004)]) - Fixed `compat/chunk` to return an empty array for an empty collection with an `Infinity` size. (\[[#1995](toss/es-toolkit#1995)]) - Fixed `compat/lastIndexOf` to read holes in sparse arrays as `undefined`. (\[[#1977](toss/es-toolkit#1977)]) - Fixed `compat/last` to return `undefined` for empty array-like inputs. (\[[#1954](toss/es-toolkit#1954)]) - Fixed `compat/pullAll` to return the array as-is when `values` is nullish. (\[[#1962](toss/es-toolkit#1962)]) - Added a browser compatibility test suite. (\[[#2012](toss/es-toolkit#2012)]) - Improved documentation, JSDoc accuracy, tests, and internal refactoring across `compat` and the docs site. (\[[#1622](toss/es-toolkit#1622)], \[[#1789](toss/es-toolkit#1789)], \[[#1824](toss/es-toolkit#1824)], \[[#1844](toss/es-toolkit#1844)], \[[#1849](toss/es-toolkit#1849)], \[[#1854](toss/es-toolkit#1854)], \[[#1855](toss/es-toolkit#1855)], \[[#1859](toss/es-toolkit#1859)], \[[#1860](toss/es-toolkit#1860)], \[[#1868](toss/es-toolkit#1868)], \[[#1871](toss/es-toolkit#1871)], \[[#1887](toss/es-toolkit#1887)], \[[#1898](toss/es-toolkit#1898)], \[[#1933](toss/es-toolkit#1933)], \[[#1939](toss/es-toolkit#1939)], \[[#1947](toss/es-toolkit#1947)], \[[#1950](toss/es-toolkit#1950)], \[[#1955](toss/es-toolkit#1955)], \[[#1956](toss/es-toolkit#1956)], \[[#1957](toss/es-toolkit#1957)], \[[#1960](toss/es-toolkit#1960)], \[[#1963](toss/es-toolkit#1963)], \[[#1964](toss/es-toolkit#1964)], \[[#1968](toss/es-toolkit#1968)], \[[#1969](toss/es-toolkit#1969)], \[[#1970](toss/es-toolkit#1970)], \[[#1972](toss/es-toolkit#1972)], \[[#1979](toss/es-toolkit#1979)], \[[#1985](toss/es-toolkit#1985)], \[[#2000](toss/es-toolkit#2000)], \[[#2001](toss/es-toolkit#2001)], \[[#2021](toss/es-toolkit#2021)], \[[#2025](toss/es-toolkit#2025)], \[[#2027](toss/es-toolkit#2027)]) We sincerely thank [@Antoliny0919](https://github.com/Antoliny0919), [@D-Sketon](https://github.com/D-Sketon), [@kojesung](https://github.com/kojesung), [@chuenchen309](https://github.com/chuenchen309), [@mariazuheros](https://github.com/mariazuheros), [@DongEun02](https://github.com/DongEun02), [@raon0211](https://github.com/raon0211), [@sukvvon](https://github.com/sukvvon), [@racgoo](https://github.com/racgoo), [@dayongkr](https://github.com/dayongkr), [@Kropiunig](https://github.com/Kropiunig), [@ssi02014](https://github.com/ssi02014), [@sarathfrancis90](https://github.com/sarathfrancis90), [@mym0404](https://github.com/mym0404), [@mlnwns](https://github.com/mlnwns), [@kdelay](https://github.com/kdelay), [@gwagjiug](https://github.com/gwagjiug), [@dohwi](https://github.com/dohwi), [@blro0319](https://github.com/blro0319), [@benedictleejh](https://github.com/benedictleejh), [@amir-rezaei](https://github.com/amir-rezaei), [@ianzone](https://github.com/ianzone), [@sen2y](https://github.com/sen2y), [@rossyman](https://github.com/rossyman), [@eunwoo-levi](https://github.com/eunwoo-levi), [@ramong26](https://github.com/ramong26), [@Gdm0714](https://github.com/Gdm0714), and everyone else who contributed. We appreciate your great efforts! Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Adds seven compile-time type utilities to
es-toolkit/types, and groups the reference sidebar by category.IsEqual<A, B>truewhen two types are exactly the samePrimitiveJsonValueJSON.parsecan produceUnknownRecord{}EmptyObjectisEmptyObjectSetOptional<T, K>Partialscoped to specific keysSetRequired<T, K>Requiredscoped to specific keysReference pages are added in all four languages.
MergeandObjectKeyswere exported and documented but missing from the intro table, so they are listed there as well.Notes on a few choices
IsEqualuses the conditional-type variance trick, which is hard to write by hand and tellsanyapart from every other type. The same trick already exists incompat/_internal/Equals.d.ts; that copy is left untouched to keep this change out ofcompat.JsonValuefollows RFC 8259 and is recursive. It ships as a single self-contained type rather than aJsonObject/JsonArray/JsonPrimitivefamily, since each of those is a one-liner at the call site (JsonValue[],Record<string, JsonValue>).SetOptionalandSetRequiredboth survive a union, so each member can still be told apart afterwards. Their definitions differ, and the specs record why:Omitcollapses a union to its shared keys, soSetOptionalneeds the conditional type. An intersection leaves the union alone, soSetRequireddoes not. Both were checked against type-fest and produce identical results across the cases that matter (readonly and optional modifiers, multiple keys, unions, index signatures).Sidebar
The types were listed flat. They are now split into objects (14) / values (5) / predicate (1) through the
categoriesfield inflavors.mts, the same mechanismes-toolkit/compatalready uses. The split is by what a type takes, so the key conversion types sit with the other object types.labels.categoriesis shared across flavors, soes-toolkit/typescould not label its ownpredicategroup without changing the runtime one.buildFlavorSidebarnow looks up<flavor>:<category>before falling back to the shared key. Existing flavors are untouched.Reference pages move into matching folders, so their URLs gain a segment (
/types/reference/ValueOf->/types/reference/objects/ValueOf). Links in the intro, inside the moved pages, and coming in from the runtime function docs are all updated.Verification
vitest run src/types --typecheckpasses, 66 teststsc --strict, including the failing cases marked in commentsbuildFlavorSidebarfor all four localesdocsresolve