DEV Community

Discussion on: Why you should learn TypeScript today

peerreynders profile image
peerreynders

TIL: There needs to be a comma after the type parameter for an arrow function otherwise TS thinks it's JSX.

const wait =
  (milliseconds: number) =>
  <Value,>(executor: Executor<Value>) =>
    new Promise((resolve, reject) =>
      setTimeout(executor, milliseconds, resolve, reject)
    );
Enter fullscreen mode Exit fullscreen mode

The error message I was fighting:

"Argument of type T is not assignable to parameter of type T. T could be instantiated with an arbitrary type which could be unrelated to T."

CodeSandBox

Which seems to imply:

"The caller of the function specifies the type parameter, not the implementer"


If you refer back to my TypeScript version please note that I require Promise<T>.

Your version only gives me Promise<unknown>. The moment I put Promise<T> on rootAndRun() everything lights up red. The Promise<T> based on Factory<T> was the point of making rootAndRun() generic.

For Promise<unknown> we don't need generics to begin with. CodeSandbox

unknown is extremely useful under very specific circumstances but when overused it reminds me of the Java pre-Generic Object fiasco in terms of type safety.


that could be reused

How OO of you 😁

In this case reuse isn't the goal as this is only for testing support, so not being coupled via reuse (Beware of the Share) is a good thing.

Also in general I try to stick to the Rule of Three:

  • You must have looked at at least three systems to understand what is common across them (and therefore reusable)
  • It takes three times as much effort to make something reusable as to make it usable
  • You will receive payback after the third release.

In this case the goal was to "unroll" it enough to make it more understandable.

Thread Thread
lukeshiru profile image
Luke Shiru

Here's your CodeSandbox with the minimum fixes I would do to it. The problems I saw:

  1. executor had its own T instead of using the one from rootAndRun and Factory, so that will be taken as different generics even if you name them the same. You can see this by just renaming T to something else (F2).
  2. done has the same problem.
  3. resolve inside done expects T, but done actually passes data as T | undefined, so you have to check if data is defined before passing it to resolve.

Other than that I just added Maybe (an alias for Type | undefined that I always have around), and made some changes here and there to make my linter happy (like using error instead of err).

How OO of you 😁

Trust me, FP is all about reuse. I don't follow a "rule of N", I just try to keep my functions small and make them do one job and do it right which makes them far easier to test, maintain and reuse.

Thread Thread
peerreynders profile image
peerreynders

So my "type parameters inside closures" needs more work; figures. The Maybe makes sense, I'm constantly surprised it's not with the utility types.

I just try to keep my functions small and make them do one job and do it right which makes them far easier to test, maintain …

I'm right there with you in terms of small and focused but I'm not prescient so it's far too easy for me to fall prey to premature reuse/abstraction—OO or functional.

Thank You for the assist!