Typescript Study
Typescript Cell
Odisea - I view code as a gateway to endless possibilities. It can be easy to get side tracked and chase down rabbit holes but by staying focused, you can quickly build towards something special. However, chasing down those rabbit holes can lead to new growth so it's important to make time to study.
Goals
In this article I want to demo a feature I've built into my blog so that visitors can not only read the code I'm describing but also edit and run it to test out other ideas. After all the best way to learn how something works is to break it.
Markdown Compatibility
Since my site used markdown for my pages, the first task I had was to create a way to inject code from a markdown file into a new cell component. Since I use Markdoc under the hood I was pretty straight forward to parse markdown into custom components using a bit of syntactical sugar.
Ultimately I settled on this:
# A basic code snippet
```typescript
const two: number = 3
const three: number = 3
```
# An editable code snippet
{ % typescript-cell % }
```typescript
const two: number = 3
const three: number = 3
```
{ % /typescript-cell % }
This makes it super easy to swap between basic code presentation and the new editor while preserving all the language highlighting rules in my VSCode while editing the post's markdown file.
Client Web Editor
Next up was the actual editor that would be used in the browser. For this I've previously used Codemirror and was happy to find a package that it super simple to use with React.
TypeScript Linting
Because the the whole point of using typescript is to catch simple issues that arise from syntax mistakes, I wanted to make sure my web editor had the same capabilities.
This Linting feature was probably the part that gave me the most headache. I think part of the problem was that Googling for other projects like this was not simple since all the keywords such as "typescript", "linter", "nextjs", and "codemirror" all had a huge amount of results for your more standard issues.
Ultimately after much surfing, I found a package that utilized workers to run a TypeScript server on the client. With this in hand, I simply had to wrap my head around how to get this to play nice with NextJS.
Themeing
Once the editor was loading in correctly and the workers were happy with NextJS, the next thing was to make the editor more consistent with what my existing code snippet block looked like. This probably could have waited till after I had code execution, but it was a nice breather after having fought with multiple failed attempts at finding the right combination of tools and configuration for the editor/linter.
Code Translation
In order to run this code in the browser I need to first convert it to javascript. The TypesScript linting step is already doing this, however, I need a way for console.log to be swapped out with a custom helper than can print to the dom instead. Additionally, I'm not sure how much sanitization is required so this is a step I'll have to look more into.
Code Execution
The final step would be to simply run the js code like normal after the translation step.
Demo
// comment
const two: number = 's'
const three: number = 3
const status: boolean = true
const valid: null = null
const element = () => {
return null
}
class S {}
const sum = two + three
if (sum !== 5) {
console.log('something went wrong')
}
if (sum !== 5) {
console.log('something went wrong')
}
if (sum !== 5) {
console.log('something went wrong')
}
Resources
- https://markdoc.dev/
- https://codemirror.net/
- https://github.com/uiwjs/react-codemirror
- https://github.com/val-town/codemirror-ts
- https://github.com/alangpierce/sucrase