Personally, I don't use classes much, but sometimes I think free functions are a little too hard to find, so I tend to experiment with the following pattern.
interface User { … }
const User = {
rename(user: User, newName: string): User { … },
getDisplayName(user: User): string { … }
}
const renke: User = { … }
console.log(User.getDisplayName(renke));
Which makes finding an operation for a certain type easier to find (just write User and trigger autocomplete).The alternative is of course having renameUser (or userRename) and getUserDisplayName (or userGetDisplayname). The prefixed version would make autocomplete easier also.
However, there is also a different proposal that touches different similar issue which might fix this too: The bind operator proposal [2].
Like the name implies, it allows to set the `this` for a function call. This opens the possibility to implement the common map/filter/reduce functions in a lazy manner _for arrays_. Taken from the samples, this could evaluate lazily on an array returned by `getPlayers()`.
import { map, takeWhile, forEach } from "iterlib";
getPlayers()
::map(x => x.character())
::takeWhile(x => x.strength > 100)
::forEach(x => console.log(x));
Of course, this could also be used for iterators. However, the binding operator is not very active any more.[1]: https://www.proposals.es/proposals/Iterator%20helpers [2]: https://github.com/tc39/proposal-bind-operator
I also missed the awesome bind-operator. EG:
const getFoo = () => this.foo;
const bar = { foo: 1 };
console.log(bar::getFoo()); // 1
https://github.com/tc39/proposal-bind-operator function f() { return this + 5; }
But there are only two ways to call it: f.call(5) // calls with `this` argument set to 5
and let x = new Number(5)
x.f = f;
x.f(); // syntax sugar for to x.f.call(x)
The confusing part here is that `x.f()` is very different from `x.f`, and is most definitely NOT the same as `(x.f)()`, but more of an `(x.f).call(x)` Other than that and the fact that the argument is always there even if you don't specify it, its exactly the same as Lua, metatables (prototypes) and all.To resolve this confusion once and for all, we desperately need the bind operator [1] to provide a primitive on top of which the rest can be explained.