4 ms·
Python-Style Kwargs in TypeScript
- lloydatkinson 1y agoI don't really like this at all. I'm not familiar with Python but this kwargs sounds like it leads to inconsistency throughout usages of a function. In JS/TS it's a lot more conventional to use objects once you go past 2-3 arguments. Sometimes patterns from other languages are great in other languages (like, functional ways of modelling errors, making invalid state impossible, not using nulls, etc), but other patterns like the one shown here don't seem great.
- rafram 1y agoHmm? “Use objects once you go past 2-3 arguments” seems to be exactly what this post is arguing for. (Which, as you say, is not novel and is common in browser APIs and other JS libraries.) Not sure what you’re disagreeing with.
- nrawe 1y agoI agree the problem, but the given solution feels a bit clunky to me. From a syntax perspective, passing an options object and applying it over a set of defaults feels a lot cleaner. The reason kwargs work in Python is primarily because the syntax is clean on both the caller and callee's side of things. This puts a lot of additional non-obvious syntax on the callee side.
- jarredkenny 1y agoTLDR: Typescript has objects and destructuring. If you squint it kinda looks like Python's kwargs, because both JS objects and Python kwargs are simply key value pairs.
- lerp-io 1y agoObject destructuring with default parameters is a JavaScript feature.
- SwiftyBug 1y agoI use that approach to group options in a single parameter. But then not only the options parameter must be nullable, but also its properties: function findAll(tableName: string, opts?: { where: Record<string, any>; limit?: number; sort?: "DESC"| "ASC" }) {}
- Waterluvian 1y agoI don’t like how dang busy it gets. What I do is if I need more than a few args, I accept only an object. And offer only type information in the signature, and resolve default values at the start of the function. It even works nicely if all args are optional.
- game_the0ry 1y ago^^ this I would probably do the same before using kwargs.
- Izkata 1y agoThey are passing "prefix", "ending", and "extraNames" in an object. It's just defined inline in the function and using destructuring so the function can access the keys by name without having to put the object in a variable (and the default values are part of the object destructuring).
- Waterluvian 1y agoYeah but to have half-decent typings you then have to define the entire type, again, in the signature.
- williamdclt 1y agoMy personal philosophy, which isn't shared by many but I'm yet to find it failing me: (almost) never use default arguments. It's bad design and causes real issues, between bugs and incidents I've been involved in dozens of situations where I've found that "this would never have happened if this argument didn't have a default value". First, there's very rarely a value that really makes sense to be the "default". People often use a default value when it's a "commonly used" value: I don't think it's a good reason, other values usually are just as valid and important as the most-commonly-used value. It's like saying someone in Sweden is "white by default" because it's the most common case: it's going to be often correct but _why would you do that_ when you could just make it explicit. The typing you're saving isn't worth it. Second, it makes your API less easy to use. Devs _should_ read through all the available arguments anyway to make your function do what they want, including these default arguments (even if they decide not to set them), so what did you gain from making them optional? A bit of typing, a bit of screen real estate? Sure, but devs _do not actually behave like that_ and often don't read or don't pay enough attention to optional arguments. They just (consciously or not) hope that the default values will be reasonable for their specific use-case. Well, too often it's not and that result in a bug or incident: the typing and screen estate you gained are not worth it. FORCE devs to think about what's the correct value, that's good design. Third, it's much less readable. The reader doesn't know that there are invisible arguments with an implicit value, despite these arguments modifying the behaviour of the function. Make everything explicit and no-one needs special implicit knowledge to know what a function is doing (even Python says "explicit is better than implicit"). Fourth, what would make sense as a default at some point might not make sense later. You pick a default that seems to make sense, people use this default value all over the place, things change and actually new use-cases usually need a different value... well sucks to be you. Now you have a footgun, as it's not even a good default for new use-cases and it's more likely to be misused, or you need to go over all previous use-cases to give an explicit value so that you can change the default... might as well have never made it a default. There's exceptions of course: I wouldn't want `key` or `className` to be explicit in React, but for 99% of backend stuff, default values are a bad design. I hate Go for this: zero values have caused _countless_ issues to almost everyone I know, whether they acknowledge it or not.
- egroat 1y ago
- lbreakjai 1y agoThe first code example on the article is wrong. It would print "!, Bob." and not "Hello, Bob!".
- deleted 1y ago[deleted]
- thrance 1y agoSo, an entire article just telling you to put objects as the last parameters to functions? Wow thanks, I'd have never thought of that.
- Garlef 1y agoTL;DR + Some extra: * 1-2 args: fn(arg1, arg2) * More args: fn({ arg1, arg2, arg3, ... }) * Sometimes: fn(mainArg, { ...optionObject })
- sestep 1y agoI personally kind of feel like no existing language provides great syntax for structured function parameters. I recently wrote a post about how I think languages could make this better in general (although one thing I didn't tackle in my post is default values for arguments, which is very important): https://samestep.com/blog/parameter-syntax/ https://samestep.com/blog/parameter-syntax/
- instig007 1y agoYou can do most of it in default Haskell syntax, plus `RecordWildCards`: https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/record_wildcards.html https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/reco...
- sestep 1y agoOh interesting; is that actually true? I'm not aware of Haskell features that allow it to do better than any of the three other languages I compared to in my post. What would my running example look like in Haskell?
- instig007 1y agoHere's the sample you can play with (interactive: https://play.haskell.org/saved/TWBEYFzH https://play.haskell.org/saved/TWBEYFzH): {-# LANGUAGE RecordWildCards #-} main = transport ("2025-09-05T09:00:00Z", "2025-09-05T11:00:00Z") foo123 kwargs where foo123 = Foo kwargs = Kwargs {..} bar = Bar person = Person {..} name = "Alex Smith" phone = "+1 (555) 555-5555" options = Opts {..} fragile = True window = PM data Foo = Foo data Bar = Bar data Kwargs = Kwargs { bar :: Bar , person :: Person , options :: Opts } data Person = Person { name :: String , phone :: String } data Opts = Opts { fragile :: Bool , window :: HalfDay } data HalfDay = AM | PM transport (start, end) foo Kwargs { person = Person{ name = who, ..}, options = Opts{..}, ..} = do doStuff who foo moreStuff phone end window otherThings start fragile bar doStuff who foo = print "called doStuff" moreStuff phone end window = print "called moreStuff" otherThings start fragile bar = print "calle otherThings"
- quink 1y agoJust make it a well-defined class. Like option structs in Go. Simple.
- seivan 1y agoThat would pollute the namespace. The type could be namespaced under the function signature, it's not its own type unless you extract it with FunctionParamater<typeof ..>[0] or along those lines.
- techlatest_net 1y ago[dead]
- seivan 1y agoI wish rust and typescript had this builtin. Obj-C and Swift spoiled me. Named/keyword arguments is worth the verbosity. Maybe not Obj-C-tableViewcellForRowAtIndexPath level, but still.