Why I Have Not Used TypeScript in My NotWP Project

1 views
Why I Have Not Used TypeScript in My NotWP Project

There is a pervasive silence that falls over a room of engineers when you suggest that perhaps, just perhaps, TypeScript is not the silver bullet we have all been promised.

It feels akin to walking into a cathedral and loudly questioning the structural integrity of the pews.

We are living in an era where tooling has become a religion.

The complexity of our build pipelines is often worn as a badge of honour rather than viewed as a necessary evil that we should be trying to minimise.

I have spent the better part of the last decade building for the web, watching frameworks rise and fall like tides.

I remember the early days of jQuery, where the magic lay in the fact that you could simply drop a script tag into an HTML file and watch the page come alive.

It was messy, certainly.

It was chaotic, undoubtedly.

But it was also incredibly alive and immediate.

As I embarked on the architecture for NotWP, my latest project which aims to rethink how we approach content management, I faced a crossroads that every modern technical lead faces.

Do I follow the herd and adopt the strict, typesafe rigorousness of TypeScript?

Or do I take the path less travelled and stick to the dynamic, untethered freedom of vanilla JavaScript?

The pressure to choose the former is immense.

If you browse the job boards on LinkedIn or look at the most popular repositories on GitHub, you will see a sea of .ts files and complex interface definitions.

It has become the default setting for "serious" software engineering on the frontend.

However, after deep reflection and a rigorous analysis of my goals for NotWP, I chose to reject TypeScript.

This was not a decision made out of ignorance or an unwillingness to learn new tools.

I have used TypeScript extensively in corporate environments and large-scale enterprise applications.

I know how to write generics.

I understand the utility of discriminated unions.

I appreciate the intelligent autocompletion that modern editors provide when the types are lined up in perfect rows.

Yet, for this specific project, I believe TypeScript is an impediment rather than an aid.

The illusion of velocity and the bicycle analogy

There is a thoughtful article I read recently that perfectly encapsulates my feelings on this matter, published back in late 2020.

The author uses a brilliant analogy involving bicycles to describe the difference between the JavaScript and TypeScript experience.

Imagine two bicycles that look identical, but one—the TypeScript bike—requires you to install your own tyres before you can ride it.

That alone is a friction point, but one we often forgive.

But then comes the expansion kit, the training wheels that are sold as optional but eventually become mandatory cultural enforcers within a development team.

The author argues that while the TypeScript rider is busy fiddling with their expansion kit, putting training wheels on the front and back, and ensuring every bolt is tightened to a specific torque specification, the JavaScript rider is already half a mile down the road.

The JavaScript rider might wobble.

They might even graze their knee.

But they are moving.

They are learning the terrain of the road by feeling it beneath their wheels, not by studying a map of what the road is supposed to look like.

In the context of NotWP, velocity is everything.

We are not building a banking application where a single type error could result in millions of pounds lost in a transaction.

We are building a creative tool for publishing.

The cost of "fiddling with the bike" is simply too high when we are trying to race against the stagnation of the current CMS market.

The author of that piece rightly points out that TypeScript often makes sense for mature projects where the goal is to not fail.

But what if your goal is to succeed?

What if your goal is to innovate and discover new patterns that a rigid type system might not even have a name for yet?

When you are in the explorative phase of a project, you do not know the shape of your data yet.

You are sculpting clay, not cutting diamonds.

To define an interface for a data structure that might change three times before lunch is a waste of mental energy.

It forces you to codify your ignorance.

You end up writing types that are either too loose to be useful (the dreaded any) or so strict that they require a massive refactor every time you have a new idea.

This is the antithesis of the creative process.

The barrier of exclusion

One of the most critical reasons I chose to eschew TypeScript for NotWP is fundamentally about people, not code.

I have a vision for this project that extends far beyond my own contributions or those of a small, elite core team.

I want to involve as many developers on this project as possible, and TypeScript actively restricts that goal.

The web was built on the premise of democratisation.

Sir Tim Berners-Lee did not design the World Wide Web to be a walled garden accessible only to those with a Computer Science degree and a mastery of transpilers.

HTML and JavaScript are, by their very design, permissible and forgiving.

They allow you to make mistakes.

They allow you to experiment.

When we introduce TypeScript into a project, we are raising the drawbridge.

We are telling potential contributors that before they can fix a typo in a button label or tweak the colour of a header, they must first understand our build chain.

They must understand how to satisfy the compiler.

They must navigate the often cryptic error messages that arise when types conflict.

This is a massive filter that screens out a huge demographic of talented creators.

I want designers who code to feel welcome in the NotWP repository.

I want junior developers who are just cutting their teeth on logic flow to feel that they can make a meaningful contribution without being shouted at by a linter.

I want hobbyists who code only on weekends to be able to clone the repo and have it running in seconds, not minutes.

There is a famous quote by the interface designer Bret Victor that resonates with me in this context.

He said, "A tool addresses a human problem by modifying the human problem representation."

If the representation of our problem requires a PhD in type theory to understand, we have failed to build a good tool for collaboration.

TypeScript creates a class system within development teams.

There are the "architects" who understand the complex generic wrappers and the "implementers" who just try to get the red squiggly lines to disappear so they can ship their feature.

This is toxic for an open source community.

By sticking to JavaScript, we are using the lingua franca of the web.

It is the language that is natively understood by the browser.

There is no compilation step required to understand the source of truth.

What you write is, for the most part, what runs.

This lowers the cognitive load for everyone involved.

It invites curiosity.

It says, "Come in, the water is fine, and you do not need special equipment to swim here."

The exclusion is not just about skill level, but also about the diversity of background.

Many self-taught developers start with the basics of the web stack.

They learn by "viewing source" and tinkering.

TypeScript obfuscates the source.

It adds a layer of abstraction that separates the learner from the machine.

If NotWP is to be a platform that belongs to the community, it must speak the language of the community, not the language of the enterprise compiler.

The overhead of the build chain

We often underestimate the sheer weight of the tooling required to support a TypeScript environment.

It is never just tsc.

It is the configuration file, tsconfig.json, which has dozens of options that can subtly change how your code behaves.

It is the integration with your bundler, be it Webpack, Rollup, or Vite.

It is the friction added to your testing framework.

It is the need to find type definitions for every third-party library you wish to use.

How many times have you found a perfect little utility library on npm, only to realise it doesn't ship with types?

You are then left with two bad choices.

You can write the type definitions yourself, effectively taking on the maintenance burden for code you didn't write.

Or you can add a // @ts-ignore comment and feel a slight pang of guilt that you are "doing it wrong."

In the NotWP project, we aim for minimalism.

We want the distance between a developer having an idea and that idea appearing on the screen to be as short as possible.

Every step in the build chain adds latency to that loop.

It adds seconds to the hot-reload cycle.

It adds minutes to the CI/CD pipeline.

These moments add up.

They break the flow state.

When you are deep in a problem, maintaining a mental model of a complex system, a five-second pause to wait for a transpiler can be enough to topple your house of cards.

Furthermore, the debugging experience in a TypeScript environment is often disjointed.

You are writing code in one language, but debugging it in another.

Source maps have improved significantly over the years, but they are not infallible.

There are still moments where the line number in your stack trace does not quite match the line number in your editor.

This adds a layer of doubt to the debugging process.

You have to wonder, "Is this bug in my logic, or is it an artifact of the compilation process?"

With vanilla JavaScript, that doubt is removed.

The code you see in the Chrome DevTools is the code you wrote.

The transparency is total.

This aligns with the philosophy of "What You See Is What You Get," a core tenet of the NotWP user experience that we want to mirror in the developer experience.

Alternatives to the type safety cult

The proponents of TypeScript will argue that without it, you are writing unsafe code.

They will say that you are inviting a plague of "undefined is not a function" errors.

They will claim that refactoring is impossible without the safety net of the compiler.

I believe these claims are exaggerated and stem from a lack of knowledge about modern JavaScript tooling.

We can achieve a very high degree of confidence and safety without the overhead of TypeScript.

Tools like ESLint have become incredibly sophisticated.

They can catch a vast array of potential errors through static analysis without requiring a type system.

We can use JSDoc comments to hint at the shape of our data.

This provides the best of both worlds.

Modern editors like VS Code—ironically built with TypeScript—can read these JSDoc comments and provide the same IntelliSense and autocompletion that TypeScript users crave.

We get the documentation.

We get the autocompletion.

We get the warnings if we pass the wrong number of arguments to a function.

But we do not get the build step.

We do not get the runtime erasure of our work.

We keep the code as standard JavaScript that can run in any environment that supports the ES standard.

If you are interested in seeing how effective this approach can be, I recommend looking at the documentation for the Closure Compiler or simply reading the JSDoc guides on the Mozilla Developer Network.

You can find excellent resources on the MDN Web Docs that explain how to document your JavaScript effectively.

There is also a growing movement in the Svelte community, led by Rich Harris, shifting library development back to JSDoc.

This is not a regression.

It is a simplification.

It is a realisation that we can have nice things without paying the heavy tax of a transpiler.

Refactoring in vanilla JavaScript does require a robust test suite.

But you should have a robust test suite regardless of whether you use TypeScript or not.

Types are not a replacement for tests.

A type system can tell you that your function expects a string and returns a number.

It cannot tell you if that function actually calculates the correct number.

By relying on tests rather than types for safety, we are forced to write better tests.

We are forced to think about behaviour rather than structure.

This ultimately leads to more resilient software.

The creative constraints of strict typing

There is a psychological aspect to programming that is often overlooked.

The tools we use shape the way we think.

When you work in a strictly typed language, you tend to think in terms of hierarchies and contracts.

You start to design your system by defining the nouns.

What is a User?

What is a Post?

What is a Comment?

You lock these definitions down in .d.ts files before you have even written the code that uses them.

This is the "waterfall" methodology disguised as modern tech.

It assumes you know the final state of your system at the beginning.

When you work in a dynamic language like JavaScript, you tend to think in terms of verbs and transformations.

How does data flow?

How does it change?

You are free to pass an object through a pipeline of functions, tacking on new properties as needed, stripping others away.

This "duck typing"—if it walks like a duck and quacks like a duck, it is a duck—allows for a much more organic evolution of the software.

In the NotWP project, we are dealing with unstructured content.

We are dealing with plugins that might want to inject data we never anticipated.

If we were to model this in TypeScript, we would end up with a nightmare of generics and Record<string, any> types.

We would be fighting the type system at every turn.

By embracing the dynamic nature of JavaScript, we align ourselves with the reality of the data we are handling.

We accept that the web is messy.

We accept that content is unpredictable.

We build our system to be resilient to that unpredictability at runtime, rather than trying to legislate it away at compile time.

This approach requires a different kind of discipline.

It requires defensive programming.

You have to check your inputs.

You have to handle the case where a property might be missing.

But this results in code that is robust in the real world, not just in the sterile environment of the IDE.

As the source article mentioned, the TypeScript bike might be safer in a controlled environment, but the JavaScript rider learns to survive the fall.

That experience of handling runtime errors, of building safeguards into the logic itself, makes for a better developer.

It creates an "improved rider on a leaner craft."

The false promise of "Enterprise Ready"

There is a tendency in our industry to conflate complexity with quality.

We look at the massive codebases of Google or Microsoft and assume that because they use a certain tool, we must use it too if we want to be "professional."

But NotWP is not Google.

We do not have a thousand engineers working on the same monorepo.

We do not have the communication overhead that necessitates strict contracts between teams.

We are a small, agile group of creators.

Adopting enterprise-grade tooling for a project of our scale is like renting a container ship to deliver a pizza.

It is overkill.

It is wasteful.

And it is slow.

The great computer scientist Donald Knuth once famously said, "Premature optimisation is the root of all evil."

I would argue that premature strictness is a close cousin to premature optimisation.

We are optimising for a scale we have not yet reached.

We are optimising for a maintenance burden we do not yet have.

We are paying the cost of bureaucracy before we have even established a government.

There is a beauty in the "Worse is Better" philosophy that Richard Gabriel wrote about.

The idea that simplicity of implementation and interface is more important than correctness or consistency.

JavaScript embodies this.

It is not a perfect language.

It has warts.

It has oddities.

But its implementation is simple, and it is universally available.

By choosing JavaScript, we are choosing the path of least resistance.

We are choosing to spend our innovation tokens on features that the user can see, rather than on architectural purity that only the developers can see.

Looking at the long term

Some will argue that I am being short-sighted.

They will say that in two years, when the NotWP codebase has grown to fifty thousand lines, I will regret this decision.

They will predict that we will be drowning in technical debt.

I respectfully disagree.

I have maintained large legacy JavaScript codebases.

They are manageable if the code is written with care.

Clean code is not dependent on static analysis.

Clean code is about separation of concerns.

It is about naming things well.

It is about writing small, composable functions.

None of these require TypeScript.

If, in the future, we decide that certain core modules of NotWP need to be hardened, we can introduce type checking incrementally.

That is the beauty of the modern ecosystem.

It does not have to be all or nothing.

But to start with the shackles on is a mistake.

It stifles the initial burst of energy that is required to get a project off the ground.

I want the development of NotWP to feel like play.

I want it to feel like sketching.

When you use TypeScript, it feels like drafting legal documents.

Every interaction must be scrutinised and notarised.

It drains the joy out of the act of creation.

And let us not forget the dependency hell that often accompanies the TypeScript ecosystem.

Breaking changes in TypeScript versions.

Incompatible type definitions between libraries.

The endless game of catch-up.

By avoiding this, we keep our dependencies leaner.

We rely closer to the platform.

The web platform itself is incredibly stable.

Code I wrote ten years ago in vanilla JavaScript still runs today in modern browsers.

Can we say the same for code written in early versions of Angular or heavy build-dependent frameworks?

Longevity comes from simplicity.

Longevity comes from adhering to standards, not supersets.

A call for simplicity

We are drowning in complexity.

Every year, the frontend stack gets deeper and more opaque.

We add layers upon layers to solve problems created by the previous layer.

I am choosing to step off this treadmill.

I am choosing to build NotWP with the tools that the web gave us.

I am choosing to trust my developers to write good code without a compiler holding their hand.

I am choosing to prioritise the speed of iteration over the safety of the type system.

This is a risk, yes.

But as the source article asks, what is the goal?

Is it to not fail?

Or is it to succeed?

I want NotWP to succeed.

I want it to be vibrant, accessible, and fast.

I want it to be a bicycle that anyone can hop on and ride, without needing to read a manual or install a kit.

If that means we scrape our knees occasionally, so be it.

We will heal.

We will learn.

And we will keep moving forward.

The famous French writer Antoine de Saint-Exupéry wrote, "Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away."

I am taking away the build step.

I am taking away the transpile time.

I am taking away the generic interfaces.

I am taking away the barriers to entry.

What is left is the code.

Pure, simple, executed exactly as written.

And for NotWP, that is enough.

We invite you to join us.

You do not need to install anything.

You do not need to configure anything.

Just open the file, and start creating.

That is the web I fell in love with.

And that is the web I want to help preserve.

If you are interested in the philosophy of simple software, I highly recommend exploring the works of the suckless.org community.

They champion software that is focused, simple, and minimal.

While they focus mostly on C and desktop utilities, their philosophy applies beautifully to the web.

Software should be brush strokes, not bricklaying.

It should be fluid.

It should be human.

TypeScript, for all its merits in the corporate world, feels like a layer of concrete poured over a garden.

It keeps the weeds out, sure.

But it prevents the wildflowers from growing.

With NotWP, we are planting a garden.

We are letting the chaos of organic growth happen.

We trust that the result will be something far more interesting than a perfectly manicured lawn.

So, keep your training wheels.

We are going for a ride.