Is it possible to create Kotlin like scope functions in Javascript/Typescript? Is there any library that does it?
Reference: https://kotlinlang.org/docs/reference/scope-functions.html
Is it possible to create Kotlin like scope functions in Javascript/Typescript? Is there any library that does it?
Reference: https://kotlinlang.org/docs/reference/scope-functions.html
No, you can't do that in JavaScript or TypeScript. But depending on why you're trying to do it, destructuring can help.
The closest you can get is to use the deprecated with statement (I don't recommend it), which adds an object to the top of the scope chain, so any freestanding identifier references are checked against the object's properties:
function example(o) {
with (o) { // deprecated
console.log(answer);
}
}
const obj = {
answer: 42
};
example(obj); // Outputs 42
There are several problems with with, though, which is why it's disallowed in the strict variant of JavaScript (which is the default inside modules, class constructs, and other new scopes created in ES2015+, as well as any function or script with "use strict"; at the beginning). Those same problems are why it's not supported in TypeScript (TypeScript will copy it over to the transpiled JavaScript code, but with an error, and it will use any as the type of symbols inside the with; example).
Another close version is to pass an object to a function that uses destructuring in its parameter list:
function example({answer}) {
console.log(answer);
}
const obj = {
answer: 42
};
example(obj); // Outputs 42
but a major caveat there is that you can't assign new values to properties that way (and worse, if you try — for instance, with answer = 67 — it updates the parameter's value but not the object's property value).
To deal with that, you might use destructuring inside the function instead, with const so you don't forget you can't update the value (or to get an early error if you try):
function example(o) {
const {answer} = o;
console.log(answer);
// answer = 67; // <== Would cause error
// o.answer = 67; // <== Would work
}
const obj = {
answer: 42
};
example(obj); // Outputs 42
Object.prototype.let = function (fn) { return fn(this); }. The scope chain itself is not altered (unlike with with), but they can allow for a more functional programming style. Of course, whether this is useful depends again on the desired use cases. scope-extensions-js is a small TS library which uses this technique.Object.prototype, it's important not to do it that particular way, because it creates an enumerable property on Object.prototype which will mess with poorly-thought-out for-in loops. Instead, use Object.defineProperty(Object.prototype, "let", { value(fn) { return fn(this); }, configurable: true, writable: true }); so the property is non-enumerable. (And all the caveats about extending native prototypes apply. E.g., never do it in a library, but in your own page/app, it can be okay.) :-)with is not supported in TypeScript: stackoverflow.com/questions/21067477/…with is deprecated largely because you can't look at the code and reason about what's what (static analysis) -- which is what TypeScript kinda wants to do. :-DIf anyone is still looking for an answer, there is an excellent library for those scope functions for javascript (I am not affiliated):
While not exactly what you're looking for, a pattern that I use let a lot for in Kotlin is
val thing = nullable?.let{ // case if not null } ?: run { // case if null }
The closest I've come to this in Javascript (well, typescript) in terms of readability and ergonomics is something like:
const thing = some?.deeply?.nested?.nullable?.thing ?? (() => {
// case if null
})
Which gets you halfway there. :)
let accepts as an implicit it parameter a non-nullable version of the variable you applied let to. In JS, the lambda after the nullish-coalescing operator has no idea whether the variable is null, since it may have changed (the current value is not captured).
some.expression(value).which?.couldBe?.null().let(someMethodToBeCalledWithExpressionAsParamIfNotNull)