> I don't write Kotlin, but what that does (assuming I'm guessing at it correctly) requires far more awkward code in most other languages
You're NOT assuming correctly. In Kotlin, this would be handled as an extension property on the Request type. You could write it just like normal code instead of extending some global ambient interfaces.
val Request.foo: Bar = whatever
get("/") { req.foo // just a method call }
You can CMD+Click on it and read the actual implementation (instead of generated type definitions).
The Typescript ecosystem needs these complicated types because of some design choices (no type based dispatch). I suggest looking up how other languages solve these problems. You'll find that in typescript, you have to reach for complex types far sooner than in other languages.
So if I pass that Request option to another function that expects a Request object, the compiler is going to track that I’m using an extended object instead of the actual Request type in the function signature and allow me to access the “foo” property?
That’s what I’m specifically talking about. Yours is just dependency injecting a type, which is more avoiding the existing types in the library. That would be the “wrapping” option I was talking about. You don’t need to extend the types if you’re just going to dependency inject them. You could just have an entirely separate object that you pass around at that point.
If the other method has visibility of my foo property, then it can call it. Nothing is being "injected" anywhere. It's the moral equivalent of foo(req). It's statically dispatched
That is exactly dependency injection, the functions have to be embedded into a scope that has access to additional values because the framework doesn’t support passing them directly. The types are injected into the function by being embedded into another scope.
It’s not some kind of moral sin, but it is a kludge. The type system is now tied to the structure of your code, because scoping is now intrinsic to your types.
It’s not the end of the world, I’ve worked in similar systems, it just tends to have a heavy mental overhead at some point as you now have to keep scoping in mind as part of your types.
You're NOT assuming correctly. In Kotlin, this would be handled as an extension property on the Request type. You could write it just like normal code instead of extending some global ambient interfaces.
You can CMD+Click on it and read the actual implementation (instead of generated type definitions).The Typescript ecosystem needs these complicated types because of some design choices (no type based dispatch). I suggest looking up how other languages solve these problems. You'll find that in typescript, you have to reach for complex types far sooner than in other languages.