[HN Gopher] Show HN: SuperUtilsPlus - A Modern Alternative to Lo...
___________________________________________________________________
Show HN: SuperUtilsPlus - A Modern Alternative to Lodash
Hey HN! After years of wrestling with Lodash's quirks and bundle
size issues, I decided to build something better. SuperUtilsPlus is
my attempt at creating the utility library I wish existed. What
makes it different? TypeScript-first approach: Unlike Lodash's
retrofitted types, I built this from the ground up with TypeScript.
The type inference actually works the way you'd expect it to.
Sensible defaults: Some of Lodash's decisions always bugged me.
Like isObject([]) returning true - arrays aren't objects in my
mental model. Or isNumber(NaN) being true when NaN literally stands
for "Not a Number". I fixed these footguns. Modern JavaScript:
Built for ES2020+ with proper ESM support. No more weird
CommonJS/ESM dance. Actually tree-shakable: You can import from
specific modules (super-utils/array, super-utils/object) for
optimal bundling. Your users will thank you. The best parts IMO:
compactNil() - removes only null/undefined, leaves falsy values
like 0 and false alone differenceDeep() - array difference with
deep equality (surprisingly useful) Better random utilities with
randomUUID() and randomString() debounce() that actually works how
you expect with proper leading/trailing options Also genuinely
curious - what are your biggest pain points with utility libraries?
Did I miss any must-have functions?
Author : dhax_or
Score : 75 points
Date : 2025-05-24 13:03 UTC (9 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| gaaaaaaaarf wrote:
| Nice work! Reminds me of https://github.com/angus-c/just
|
| Suggestion: add more tests and run some benchmarks
| dhax_or wrote:
| Thanks for this! I've already started adding more tests. I ran
| some benchmarks and they were really impressive. I will get it
| out in the next release
| addandsubtract wrote:
| Not to be confused with the other Just:
| https://microsoft.github.io/just/
| dannyfritz07 wrote:
| I don't think we've really seen many successors to LoDash other
| than Ramda because the platform now has many of Underscore's
| functions built in.
| 7bit wrote:
| > Like isObject([]) returning true - arrays aren't objects in my
| mental model.
|
| Correct me if I am wrong, but Array factually are JS objects and
| "[] instanceof Object" is true.
|
| Fair enough if that does not fit your mental model, but I would
| not use any library that treats facts like opinions.
| ivanjermakov wrote:
| Distinction is tricky since you can use indexing on plain
| objects, e.g. const foo = {}; foo[0]
| = "bar";
| williamdclt wrote:
| I agree with the author that it's almost never what you want.
| But I agree with you that it's the reality of the platform,
| ignoring it will cause its own problems.
|
| I'd surface the footgun rather than trying to pretend it's not
| there: isNonArrayObject and isObjectOrArray, or something like
| that
| 7bit wrote:
| Absolutely agree. I also hate that empty arrays are true,
| which is different from other languages. But I agree that
| it's better to face the reality of the language than create a
| function that evaluates [] to false. It trains you a bad
| habitnand some day that will cause you to introduce a bug.
| williamdclt wrote:
| > I also hate that empty arrays are true, which is
| different from other languages
|
| I don't mind that actually! I don't think I have much use
| cases for "empty array is semantically different from non-
| empty". Usually I find null/undefined are better choices,
| an empty array is just a normal array, I don't expect it to
| be handled differently
| 7bit wrote:
| What do you think about empty strings being falsy in most
| languages including js?
|
| Null/undefined is a better choice, but there's many
| occasions where you do not have the power of choice. For
| example with document.querySelectorAll, which returns an
| empty array if nothing is found. The simple thing to do
| is to just check for it's length or just iterate over
| it's nodes, but still. I prefer empty arrays being falsy.
|
| Just to clarify, I'm not saying one is better than the
| other. I just prefer how it works in other languages like
| Python. But I still would rather work with the JS
| language properties, than import a library that changes
| how I test for empty arrays.
| nothrabannosir wrote:
| Akshually, implicitly casting any non Boolean type to
| true or false is no better than implicitly casting "0" to
| 0. :) B-)
| 7bit wrote:
| No better based on what criteria? In what language? This
| is typical in Python and done even by core-devs. It is
| how the language was designed and it was designed to
| support that.
| dcsan wrote:
| your option is a bit more verbose but definitely more clear.
| confusing the underlying definitions of the language itself
| will lead to problems later.
| PUSH_AX wrote:
| Will it? Will it really?
|
| I've been writing JS for so long I've forgotten all these
| language quirks, I feel like it's fair for most people,
| these language choices are kind of meaningless in day to
| day, what's meaningful is a function returning things that
| will make sense to most people. Or at least have two
| functions, languageStrictIsObject()
| bryanrasmussen wrote:
| libraries of this sort, especially in JavaScript, often exist
| to enforce a more reasonable mental model rather than the model
| baked into the language.
| 7bit wrote:
| I understand that. I just don't think that it is a good
| habit. Instead of just learning the languages and it's quirks
| now you form a bad habit and start to rely on one dependency
| for all your projects.
| bryanrasmussen wrote:
| this is generally the view I have on these sorts of things
| as well, although I must admit that my views are often out
| of step with what everybody else I work with feel on the
| matter.
| _1tan wrote:
| We use es-toolkit to replace Lodash - how would you compare your
| library?
|
| We just migrated a React app with around 500k LOC and this worked
| quite well and flawless.
| dhax_or wrote:
| I've not used es-toolkit but from what I see you get lower
| bundle size, typescript support and a better performance with
| our library. I will be releasing the the benchmark soon enough
| so do watch the repository if you can
| uwemaurer wrote:
| I use es-toolkit. It is fully in Typescript. Every function
| can be imported without any extra overhead, for simple
| functions it just adds a few bytes then to the bundle. I
| doubt "better performance" since most helpers functions are
| just tiny and there is no room for significant improvements.
|
| So I think trying to be better here is pointless, better
| focus on offering more helpful utility functions which might
| be missing in es-toolkit
| redslazer wrote:
| We migrated to remeda from Lodash and are pretty happy.
| https://remedajs.com/
|
| What do you do differently?
| jokull wrote:
| I recommend https://remedajs.com/ - they're always making the
| types more accurate too. Like groupby has nonempty lists.
| gcmeplz wrote:
| The types look great on remeda, but one thing that looks
| intriguing about SuperUtilsPlus is the focus on being tree-
| shakeable. Lodash's lack of tree-shake-ability is a drawback to
| using lodash on the frontend.
|
| edit: the types on remeda look great though! If I were doing a
| backend-only NodeJS project, I'd be super tempted to test it
| out.
| bythreads wrote:
| Just import what you use for lodash?, the theres not need for
| a treeshake situation?
| yoz-y wrote:
| What I'd like is a utility library like this, but instead of it
| being an actual library, be it some utility that generates a
| single file with exports of the few functions I need. Even just
| something that would make copy pasting them easier.
|
| As in, I want actual zero dependencies, not even the library
| itself. The reason: I never want these to randomly update.
| acbart wrote:
| Couldn't you just pin a specific version dependency? My brain
| says there's some way to also pin to a hash, but that would
| require googling and I'm on mobile.
| nodewrangler wrote:
| The problem is that even if you pin to a version, at some
| point you'll need to update node, typescript, or some other
| package, and then if this package doesn't update, then you
| may have to migrate from it to something else. While js tries
| to enforce backwards compatibility, and npm, etc. help with
| the complex landscape, in practice with node, typescript,
| etc., even with LLMs helping, it can be a pita and hours or
| days of work to update at times. It's just not worth it for
| things you could've just implemented yourself. There are
| exceptions to this, though.
| mystifyingpoi wrote:
| > at some point you'll need to update node, typescript, or
| some other package
|
| I experienced both sides of this discussion (project that
| always pulled :latest disregarding any kind of versioning,
| and project that had node_modules commited inside the repo)
| and both extremes suck, but I lean towards the second one.
| I'll totally take a few days of pain over not knowing
| whether prod will work today or not.
| hinkley wrote:
| This is why running your own mirror is what most large
| companies do. Guarantee no take-backs.
| mystifyingpoi wrote:
| Pinning is a good strategy (I'd say that it should be the
| default one), but depending on your level of paranoia (think
| left-pad), you might consider just downloading the lib as it
| is, and storing it in source control forever.
| graypegg wrote:
| I do sort of miss bower [0] for this reason. It was really
| just a way to download javascript and plunk it into your
| application. It was standard practice to check all of your
| vendor dependencies into SCM. [1] Of course a good chunk of
| it was transformed through something like Gulp or Grunt
| before being added to the bower repository so you were
| unlikely to maintain those once checked in, but there was
| still quite a few packages (small jquery image gallery
| plugins and the like) that were just some un-transformed
| javascript someone typed up and threw at bower verbatim.
|
| [0] https://bower.io
|
| [1] https://addyosmani.com/blog/checking-in-front-end-
| dependenci...
| parentheses wrote:
| OOC, what is the benefit of having a "library" that requires
| such manual labor to maintain and upgrade?
|
| You'd miss out on CVEs because you don't use the common
| dependency paradigm.
|
| You'd also miss out on bug fixes if you are not detecting the
| bug itself.
|
| Help me understand because I'm with you on less dependencies
| but this does feel a bit extreme.
| hofrogs wrote:
| Why would small functions like "difference", "groupBy",
| "flatten", etc. have CVEs and require bug fixes? Implementing
| those correctly is a one and done thing
| jsheard wrote:
| You'd be surprised: https://positive.security/blog/lodash-
| ramda-underscore-vulne...
| hofrogs wrote:
| Looks like these are mostly based on "reserved"
| attributes (with double underscores that have no special
| meaning in the language, just make unintentional
| collisions less likely), a modern solution utilizing JS
| Symbol type (where needed) would have no such issues
| michaelsbradley wrote:
| Why not copy & paste the code you need into a vendor/ subdir?
|
| If the vendored code needs to be updated because of a change in
| your build tools or whatever then you'll likely be making
| similar changes to other parts of your project.
| yoz-y wrote:
| This is the approach I'm sometimes using, but it would be
| nice to have tooling around that :)
| fsloth wrote:
| Nobody wants anything _ever_ to "randomly update". Why this is
| the default setting on so many development setups boggles my
| mind.
|
| I really havent figured out why professional systems insist
| running on the bleeding edge - it's your feet are bleeding here
| I believe. 10 year ... 15 year old code is generally excellent
| if you know it through and thorough.
| skydhash wrote:
| As my experience grows, I'm getting fonder of stances like
| Debian or Common Lisp, which favors stability. Once you've
| solved a problem, it's not fun having your foundation morphs
| under you for no other reasons than bundling features and
| security updates.
| chrisweekly wrote:
| CVEs are a thing. If vulnerabilities are discovered in your
| dependency graph, choosing to ignore them can have severe
| consequences.
| programmarchy wrote:
| shadcn distribution model for utils is a good idea. i wanted
| something for react hooks as well and was surprised that didn't
| seem to exist either.
| ryancnelson wrote:
| Biggest pain point: wtf is lodash? I don't care if it's in your
| readme, but maybe tell us in your HN hype post
| cronelius wrote:
| lodash is extremely common knowledge in the js/web world.
| you're asking a chemist to explain atoms before sharing their
| big discovery
| ryancnelson wrote:
| No I'm asking a commercial that pops up in what I'm watching
| and says "ask your doctor if ciallis is right for you." and
| gives no context but someone washing their tesla.
| podgietaru wrote:
| I don't know. Maybe if it's getting a lot of traction it's
| beholden on you to look up what it is.
|
| I don't understand everything on the HN frontpage either.
| nativeit wrote:
| I dunno about anyone else, but someone washing their Tesla
| fits my mental model of impotence perfectly.
| robinson7d wrote:
| Do the example functions (isObject, isNumber,
| differenceDeep, randomUUID, debounce), along with the name
| ("SuperUtilsPlus"), and sentences saying "utility library"
| and "JavaScript" really not give enough context to get an
| idea of what this library is for?
|
| And so if Lodash is what they're trying to replace, is that
| not enough info to infer what Lodash might be?
|
| The pharma ad comparison seems more than a little
| hyperbolic to me.
| AstroBen wrote:
| Anyone who doesn't know what lodash is wouldn't be interested
| in this. It's expected knowledge for the target audience
| rgreek42 wrote:
| Weird comment
| cronelius wrote:
| I made twitter post 3 or 4 years ago making fun of Lodash team
| for _still_ not shipping loadash 5 and they didn't like it very
| much. They started working on Lodash 5 in like 2015 and it still
| hasn't shipped. Guess we make our own now
| insin wrote:
| The published version appears to be CommonJS only:
| $ node index.mjs import { isString } from 'super-utils-
| plus' ^^^^^^^^ SyntaxError: Named export
| 'isString' not found. The requested module 'super-utils-plus' is
| a CommonJS module, which may not support all module.exports as
| named exports.
|
| You might also need to update some of your type checks to handle
| wrapper objects like new String() -
| Object.prototype.toString.call(...) is your friend.
| rco8786 wrote:
| I wonder why the authors decided to make `flatten` only go one
| level deep, and have `flattenDeep` that goes N levels. AFAIK most
| other implementations of Array.flatten do it recursively through
| however many levels exist.
| meeech wrote:
| don't discount the value of a good docs site. that was one of
| things i loved about lodash that made it so easy to use, and to
| discover all the functionality it offered. So if you looking to
| replace it, would be good to have similar docs.
| thih9 wrote:
| About pain points / feature requests:
|
| Is there an idiomatic way to duplicate a hash while replacing one
| of its values, preferably something that supports nesting?
|
| Whenever I work with react and immutable structures, this comes
| up and I hack something simple.
|
| I don't do FE on a regular basis though so my perspective may be
| skewed.
___________________________________________________________________
(page generated 2025-05-24 23:01 UTC)