See also my notes on TypeScript, Nodejs, and Deno for specifics on those technologies.
Decorators
https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841
https://github.com/tc39/proposal-decorators
Fake promises
The quick method is using Promise.resolve. This will resolve as a Promise "immediately".
async function test() {
const getter = () => Promise.resolve('hi')
const x = await getter()
return x // 'hi'
}
If you want to control how long a promise takes to resolve, say for testing purposes, you can introduce a controlled timeout.
function fakePromise(value, timeoutInMs) {
return new Promise((resolve) => {
setTimeout(() => resolve(value), timeoutInMs);
});
}
async function test() {
const getter = fakePromise('hi', 1000)
const x = await getter()
return x // 'hi'
}
setTimeout
will call it's callback after timeoutInMs
. It's callback is the promise's resolve
callback. The resolve
callback takes as a parameter the data it will resolve with, which in this case is the provided value
data.
JSDoc
Dates
// returns a Unix timestamp aka Epoch time aka POSIX time.
Date.now() // 1719992541975
// returns a Date object
new Date() // 2024-07-03T07:45:03.342Z
// The above output is the same as calling the following
// This is ISO 8601 format, it is always in UTC, denoted by the Z
(new Date()).toISOString() // 2024-07-03T07:45:03.342Z
// .toJSON() returns the same value
// toString
(new Date()).toString()
If you want to create a today
and yesterday
you need to use getDate
instead of getDay
, since the former returns day of the month and the latter is the day of the week.
const today = new Date()
const yesterday = new Date(today)
yesterday.setDate(today.getDate() - 1)
This works for month, year, etc. Subtracting beyond, e.g., the first month, will correctly set to the last month of the previous year.
Library Pattern
Library Pattern in JavaScript and TypeScript
Barrel Pattern
Barrel Pattern in JavaScript and TypeScript
optional chaining and nullish coalescing
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
const x = {a: {b: 1}}
const y = x?.a?.b ?? 0
These two operators, ?.
the optional chaining operator, and ??
, the nullish coalescing operator, are similar in purpose to the ternary operators, e.g., x ? y : z
.
It is interesting to note that the right-hand side of ??
is only set when the left-hand side is null
or undefined
, and not for anything falsey, like 0
or the empty string. ??
is a more robust way to ensure a value than ||
since you can now support values like 0
or empty string as valid and only override with a default value when the input is truly undefined
(or null
).
bind this
From MDN bind docs > Creating a bound function,
A common mistake for new JavaScript programmers is to extract a method from an object, then to later call that function and expect it to use the original object as its
this
(e.g., by using the method in callback-based code).
I'm not a new programmer and make this mistake every time I return to class-heavy code. Here's an example.
class A {
b;
constructor() {
this.b = "b";
}
getB() {
return this.b;
}
}
const a = new A();
const bound = a.getB.bind(a);
const bound2 = () => a.getB();
const unbound = a.getB;
console.log(a.getB()); // 'b'
console.log(bound()); // 'b'
console.log(bound2()); // 'b'
console.log(unbound());
// TypeError: Cannot read properties of undefined (reading 'b')
Why does JS allow this behaviour? The answer is, first, that classes are syntactic sugar on top of the way javascript really handles instances, methods, and inheritance. Second, the way JavaScript really handles this is via the prototype chain, which means you can inherit "methods" from any object in your prototype chain. Under this particular paradigm, it makes sense for this
to default to the object calling the function, and not the object defining the function (which could be anywhere along the prototype chain). This means that "unbound" functions such as a.getB
expect to be called outside of the object that it was created in, with a dynamic this
value. Unbound functions are more flexible in the prototypal-inheritance paradigm than in more 'normal' class-encapsulation paradigm.
The upside of all of that is flexibility. I.e., you can capture unbound function, making certain types of code reuse possible. The downside is you have to pay attention to when you bind/unbind functions.
Log an object of arbitrary depth
console.dir(obj, { depth: null }
will log an object at any depth
typeof
The typeof operator returns a string indicating the type of the operand, aka, the entity being type-checked.
console.log(typeof 1);
// => "number"
This is a great way to safely check for the existence of a variable that might not exist. For example, modern JS/TS uses Server-Side Rendering (SSR). That means the window and document don't yet exist. Something like, window.onload = () => ...
would cause a server-side failure, since window
is not yet defined. Wrapping the call in if (window) ...
does not solve the problem because the successful evaluation of the if-clause requires evaluating window
, which is still undefined. This is why typeof
is so useful in this scenario
if (typeof window != 'undefined') ...
One final gotcha, !!(typeof window) == !!'undefined' == true
. That is, 'undefined'
is a string, not an empty, falsey string, a truthy string. You need to explicitly compare again the string 'undefined'
for the guard clause to succeed.