type Fn = <T>(a: T) => T; declare const fn: Fn; const a = fn<number>; // no "()" a; // const a: (a: number) => number
It was on the surface all along, but it eluded me.
type Fn = <T>(a: T) => T; declare const fn: Fn; const a = fn<number>; // no "()" a; // const a: (a: number) => number
It was on the surface all along, but it eluded me.
A little rant about functional programming and pure functions. There is a common delusion about pure functions. People often think that:
These statements make some point. But they are not entirely true. Let me clarify this. The only restrictions that pure functions have are:
What is a side effect? Basically, it’s any change in the world outside of the function. E.g.:
I think you got the concept. Now let’s focus on the word “side” in “side effects”. “Side” means it’s outside of the given function. We don’t have these restrictions for internal state. Yep, a pure function may have mutable internal state.
function pure(a: number, b: number): number { let c = a ** b; if (c > 100) c %= 100; return c - 14; }
^ this one is pure, even though it mutates c. Just because c is internal to the function — it doesn’t affect or depend on anything outside. We don’t mutate it after we return the value.
Ok, what about running impure functions? It’s a dangerous zone. Because it is very dependent on how exactly impure the impure function. If it’s not deterministic, then we have no chance. So the question is about: what side effects an impure function may have while still allowing us to use it inside a pure function? The answer is: the only side effect it may have is mutating the given arguments (only if they are local to the pure function):
function impure(packet: Packet): void { // deterministic and based only on packet packet.hash = computeHash(packet); } function pure(id: number, data: Data): Packet { const packet: Packet = { id, data }; impure(packet); return packet; }
Here we clearly run impure in pure. But since impure changes only packet, which is entirely managed by pure, we’re safe.
That’s it.
TIL: HTMLCollections are live-collection. What does it mean? Look. Imagine you have HTML like this:
<div> <br/> <br/> </div>
Then you want to find all its <br/>s:
const collection = $0.getElementsByTagName('br');

Thus far, everything is obvious, right? Ok, let’s add one more <br/>:
$0.append(document.createElement('br'));
So, now have three of them. Let’s read the same collection element again:

Whoa… It was updated too. Why? HTMLCollection is a “live” collection:
An HTMLCollection in the HTML DOM is live; it is automatically updated when the underlying document is changed. For this reason it is a good idea to make a copy (e.g., using Array.from) to iterate over if adding, moving, or removing nodes.
I ran into an issue. Code like this:
.link:hover { filter: brightness(1.5); }
… worked perfectly on a colored icon but had no effect on a text label. It turned out that the label used the color #000. brightness() is a purely mathematical function that multiplies the R, G, and B values by the given factor. This makes no difference for pure black, since 0 * anything = 0.
There are multiple password managers like 1pass, KeePass, and LastPass. Most of them have browser extensions. They are great. But they alter the page behavior, including HTML. Sometimes we need to prevent them from doing that.
Many years ago, people just did this:
<input autocomplete="off"
Now it doesn’t work. These extensions don’t respect this attribute. You might have seen this one:
<input data-lpignore="true"
It doesn’t work either (at least not with KeePass)
I came up with a simple and pretty silly solution:
<input type="text" onfocus="event.target.type='password'"
And it works ;-) The extensions don’t care about text-inputs. And they are not smart enough to detect new controls. At least for now.
upd: It helped with KeePass, but didn’t work out with 1Password.