This Week I Learned: About TypeScript
Why TypeScript? Aren’t you like a full-time PHP guy?
Professionally, yes, I write PHP almost exclusively. But JavaScript is the web standard. Almost all tech will be equalized being accessed through the browser. It makes sense to be at least familiar with JavaScript. All of my JavaScript knowledge was based on what I had learned in the early 2010s and I wanted to rectify that.
Deno
Deno is a JavaScript runtime to sort out a lot of the warts of node.js, led by Ryan Dahl, the same person who created node.js years ago. Ryan is also leading the effort to cancel Oracle’s trademark on the term “JavaScript,” so that people can freely title their course “Rust for JavaScript Devs” without having to worry about getting a cease and desist letter for using a trademark. Sign the petition at javascript.tm.
Deno focuses on a security model where you must authorize access to resources on your machine or remotely. Additionally, Deno runs TypeScript natively without the need for a transpilation step. This lowers the barrier for entry for a person like me. It also comes packaged with its own formatter, linter, and package manager. Fewer things to install and configure means I can start learning faster.
Deno offered a free sticker to anyone who completed at least one Advent of Code puzzle using Deno. I’m not the kind of person who wants to put stickers on things, but I thought it was fun, so I gave it a shot.
Learning Through Open-Source
I like the mission of Ryan Dahl and Deno. Hopefully not too annoying to the maintainers, I
also decided I would give back to the project and practice my TypeScript skills. I found an
open GitHub issue that seemed pretty self-contained: the cli.promptSecret()
function
needed some love. promptSecret
was designed to be used in a CLI where the user needed to
enter sensitive details into the terminal (like a password) and have the characters obscured.
The problem was that if you wrote more characters than the terminal width, it would begin to duplicate the line.
Password: ********
Password: ********
*
Password: ********
**
The input still recorded properly, but the user-experience was confusing. I decided to take a stab at it.
The previous implementation
Capture the input, store it in a variable, but don’t write it to the terminal. Write the mask
string (Password: ***
) instead, but first… we use \r\u001b[K
, a
cursor control sequence
that clears the current line and jumps the cursor to the first column in the line.
That way, we have replaced the prompt with the new masked input.
Once you’ve reached the width of the console, the next character appears on the next line, so clearing the current line and rewriting the mask is clearing the characters in the overflow line. Hence the duplication.
Password: ********
* <--- this is the current line now, so we only clear this,
but the code is rewriting "Password: *********"
The solution
We need to know the character width of the console to start. Once our masked input has reached the limit, the next character added automatically gets added to the next line. For this reason, we only need to clear/rewrite characters exceeding the width.
This works great… but what about if the user starts to delete characters and we need
to go back to the first line? We can use a different control sequence (\r\u001b[1F
) to
jump to the start of the previous line.
There was some other fun things, like realizing we don’t want to clear the current line for the first character on the new line.
It was a fun opportunity to contribute, learn some modern JS, and understand console control sequences a bit better.
Bun
Bun is another JS runtime, similar to node or Deno. It’s receiving a lot of buzz in the tech world for its speed and its big standard library. Bun offers the ability to run TypeScript without a transpilation step. I also did a handful of Advent of Code exercises in Bun [though no sticker :(] and found it easy and fast to develop with.
Interested to give back, I saw an open issue on their GitHub that noted that @types/bun
didn’t contain types for some of the recently added standard library functions.
DefinitelyTyped
DefinitelyTyped owns the @types
namespace on npm. It is a community project that allows
adding TypeScript definitions for popular libraries. Some projects are written in TypeScript,
so this is less necessary, but for projects written in JavaScript, supplementing the library
with type definitions helps give type-safety in userland code. Interestingly, anyone is
free to submit type definitions for a package. For instance, jQuery may not be interested
in adding type definitions, but a community member may create a jquery.d.ts file and submit
it to DefinitelyTyped. Then a user can include @types/jquery
in their project and not have
to deal with every function accepting and returning any
as its value.
To fix the Bun issue, all I had to do was open a PR that pointed to the latest release of bun. A maintainer of the Bun project was pinged by a bot to approve the PR, and it was available to the world.
Thoughts on TypeScript
I look forward to playing with TypeScript, Deno, and Bun more. A lot of the trepidation I had was having to relearn all of the things I missed out in the ~15 years I was away from the JavaScript world, but thanks to the wealth of free resources (and a very patient colleague), I found that getting back up to speed was pretty easy.
Admittedly, TypeScript has a type system with lots of intricacies, and I still have a lot to learn. Despite its reputation, there’s plenty that can be done without understanding the advanced topics. This makes the barrier to entry much lower than I would have expected.