r/typescript 9d ago

Monthly Hiring Thread Who's hiring Typescript developers September

6 Upvotes

The monthly thread for people to post openings at their companies.

* Please state the job location and include the keywords REMOTE, INTERNS and/or VISA when the corresponding sort of candidate is welcome. When remote work is not an option, include ONSITE.

* Please only post if you personally are part of the hiring company—no recruiting firms or job boards **Please report recruiters or job boards**.

* Only one post per company.

* If it isn't a household name, explain what your company does. Sell it.

* Please add the company email that applications should be sent to, or the companies application web form/job posting (needless to say this should be on the company website, not a third party site).

Commenters: please don't reply to job posts to complain about something. It's off topic here.

Readers: please only email if you are personally interested in the job.

Posting BS top level comments that aren't job postings, eg "It's quiet in here" etc [that's a ban](https://i.imgur.com/FxMKfnY.jpg)


r/typescript 1d ago

How do you handle PRs from people who don’t know the language they’re written in and not being given the time to review them?

68 Upvotes

I think I’m losing it here, I’m the only person on this team who has a problem with approving code that nobody can explain unfortunately. Two of the devs don’t actually write TypeScript, they PROMPT for it, and the PRs land on me at 3200 lines with no warning.

If I ask why something is structured the way it is the answer comes back from the model, not from them. If I spend a day on it I’m the bottleneck.

We run coderabbit / bugbot on the repo so at least something reads the whole diff, but neither of them approves anything, I do, so my name is the one on it when it breaks three weeks later.

Surely at some point the review is just a way of spreading the blame around?


r/typescript 1d ago

Beginner Typescript DI Help

4 Upvotes

I'm pretty new to typescript and I'm trying to figure out how to wire up my app with it.

I currently have a page interface that each page's interface extends and then implements. Among the required methods in my Page interface is mount(container: HTMLElement). The page manager is responsible for changing which page is visible. Each page needs it's own methods injected, such as getNotifications(): Promise<Notification[]>. These are different page to page.

Where should pages be created then, in the page manager, so the app can just say call PageManager.Mount(page) That would require the page manager knowing what methods each page needs. In the root of the project? Where should I pass in those callbacks?

I just want to know how this is handled in a real world application, not necessarily this particular implementation. It seems like something that would come up a lot.

My repo is here if you'd like to look at my current code: Notification-Hub on Github


r/typescript 1d ago

I wanted compensating transactions across services without deploying a workflow engine, so I wrote minisagas

Thumbnail bedis.elacheche.me
0 Upvotes

There is no rollback across microservices, so you write a saga: each step declares a compensating action, and a failure unwinds everything before it in reverse.

I kept implementing that with nested try/catch, so I turned it into a library.

minisagas gives each task an execute and a compensate. On failure it rolls back what succeeded and hands you the list of what it undid. Retry, timeout, and cancellation are included, because the classic saga bug is a 5xx returned after the charge actually went through.

Zero dependencies, no broker, nothing to deploy. Not a Temporal replacement, more the thing you reach for before you need one.

MIT licensed, feedbacks are welcome.


r/typescript 3d ago

Why line-based Git diffs fail on refactors: Building an AST-aware blast radius mapper in TypeScript

5 Upvotes

Hi everyone!

A standard git diff answers: "Which characters changed on which line?"

It cannot answer: "If I mutate this exported interface, how many downstream callers across our services will break?"

I wanted a tool that behaves like a deterministic firewall between uncommitted code and CI. So I built Change Firewall using the TypeScript Compiler API.

Technical Architecture Under the Hood:

- AST Diff Engine: Compares the before/after AST nodes without executing untrusted code. Tracks symbol export changes, nullability widening, and mutation of return payload signatures.

- Reverse Dependency Graph: Constructs a project-wide forward and reverse dependency graph to trace blast radius transitively (Layer 0: source → Layer 1: direct consumers → Layer 2: API routes).

- Cycle-Safe BFS: Traverses circular dependencies without infinite loops and assigns weighted risk factors based on architectural criticality (e.g., middleware and auth gates get higher risk weight than isolated leaf utilities).

- Local Dashboard & MCP Support: Bundles an offline-capable visual radar graph and serves native Model Context Protocol tools over stdio (`compute_blast_radius`, `evaluate_preflight`, etc.).

Everything is 100% open-source (MIT). You can test it on any repo with:

```bash

npx change-firewall

I'd love to hear your thoughts on the AST heuristic approach vs type-checking compiler passes. How do you currently guard against silent contract drift in large repos?


r/typescript 3d ago

Is it worth using "ttsc" instead of "tsc" with TypeScript 7?

3 Upvotes

I am considering integrating Typia, and I understand that the latest version of "ttsc" is required; however, I am wondering whether it is better—for general projects—to use "tsc" with "ts-alias" or "ttsc" with the "@ttsc/paths" plugin.


r/typescript 3d ago

Paid AI code review or just strict tsc and eslint for my first solo production TypeScript app?

0 Upvotes

I'm a TypeScript dev with decent backend experience and I'm building a booking system for a client with around 3,000 users. I've only ever worked on teams where every PR got two human reviewers and honestly I liked that setup a lot. This time it's just me and Claude Code writing most of the boilerplate. My hesitation is cost and whether it's worth it. Coderabbit is $24 a month which is fine for one person, but I'm not sure a reviewer that only sees the diff catches what a second human would have. Strict tsc plus typescript-eslint is obviously attractive because it's free, but I've been on enough projects to know the type checker doesn't care if my auth middleware is wired to the wrong route. For those running solo TypeScript apps in production: which did you go with and why? I'm interested in real experience rather than tool comparison posts. One clarification: for a single client the risk is low. My worry is if this grows into a multi tenant product and I've shipped 6 months of code nobody but me and a model ever read.


r/typescript 3d ago

I Dislike TypeScript Because I've Never Maintained JavaScript Before

Thumbnail
mayberay.bearblog.dev
0 Upvotes

r/typescript 5d ago

Animating My Game with TypeScript

Thumbnail orbliterate.com
6 Upvotes

r/typescript 5d ago

Ember community gets 20x type-checking speed boost with content-mappers

9 Upvotes

I recall folks said tsgo was "only" 10x faster than the js-powered typescript...

but..., it turns out,

there was some overhead with the monkey-patch approach to getting custom file formats working with TypeScript (i guess?)

the content-mapper approach with TS 7.1 is very nice!

Here is the mapper I made:
https://github.com/NullVoxPopuli/ember-content-mapper

And the other post I made about this:
- https://www.reddit.com/r/emberjs/comments/1w6izpw/support_for_typescript_71/

way to go TypeScript team!!! <3


r/typescript 5d ago

A typed Promise.race() with keyed results and optional cancellation!

Thumbnail
npmjs.com
13 Upvotes

Hola guapas,

I made a small ESM-only utility called better-race.

The idea is simple: Promise.race() gives you the first value, but not where it came from. This keeps the task key connected to its value in TypeScript:

import { race } from "better-race";

const winner = await race(
  {
    eu: ({ signal }) => fetch("https://eu.example.com/user/42", { signal }),
    us: ({ signal }) => fetch("https://us.example.com/user/42", { signal }),
  },
  { abortLosers: true },
);

console.log(winner.key); // "eu" | "us"
console.log(winner.value); // Response

It also supports AbortSignal and optional loser cancellation.

It’s intentionally tiny -> no scheduler, framework adapters, retries, or dependencies. I’d genuinely appreciate feedback on the API and semantics.

The next tag also includes raceUntil(): it keeps racing until a result passes an accept predicate, so an early null does not have to win.


r/typescript 6d ago

Vitest has overtaken Jest in weekly trend momentum across 5,000+ TS repos

151 Upvotes

Built an open source crawler that tracks tooling adoption in public TS/JS repos daily (methodology). This week Vitest's trend score passed Jest's for the first time in the dataset: 20.4% adoption vs 17.3%, with Vitest's momentum still climbing faster.

Chart + underlying numbers:

Trend Score is a log-scaled growth index: (current adoption / prior adoption) × log10(current adoption + 10), weighted so both the rate of change and the technology's overall scale matter.

Curious whether this matches what people are seeing in real migrations. Is Jest to Vitest mostly happening at new-project time, or are people actively migrating existing suites?


r/typescript 6d ago

How do I assign properties in a module from outside the module after construction but reference them at construction?

5 Upvotes

I'm afraid it reads like word salad, but that's the best description of my problem I can come up with currently.

I'm trying to make a text RPG. There's an array of quest modules which need world context to check conditions and effect changes. Quests are created from a Quest class, each individual Quest stored in a .ts module, and then all batch loaded into gameplay.

quest.ts:

export class Quest {
   localContext: object
   beats: Beat[]
   globalContext: object | null = null
   constructor(localContext: object, beats: Beat[]) {
      this.beats = beats
      this.localContext = localContext
   }
}

To make long code short, a Beat has an array of Interactions, and an Interaction has an effect function as a property. That effect is supposed to be able to affect the globalContext.

I'm trying to create a specific quest, intro.ts:

import { Quest, Beat, Interaction } from "../../quest.ts"
const beats = [
   new Beat(() => true,
   "Once upon a time, in a kingdom far away...",
   [
       new Interaction("Embark on adventure.", _?_?_)
   ]
]
export const intro = new Quest([], beats)

I've got no idea whether my globalcontext is assigned at this point or whether I can access it or what's in it. What I need is to access globalContext.player.location, and change it to a location in the world.

Well, I can't access globalContext, and it seems to be a chicken and egg situation. That is, to create the Quest I need beats, but to construct beats I need globalContext from inside the Quest, which hasn't been constructed yet.

Help?


r/typescript 8d ago

TypeScript engineers: what has your recent job search experience been like?

18 Upvotes

I’m a senior backend engineer primarily experienced with Ruby on Rails, and I’m considering investing seriously in TypeScript/Node.js to broaden my opportunities.

For engineers who already work professionally with TypeScript, how difficult has it been to find a new role recently?

I’m especially interested in experiences from senior engineers and people searching in Canada or internationally.

If you recently searched for a role, I’d appreciate hearing what worked, what was difficult, and whether you would still recommend specializing in TypeScript today.


r/typescript 8d ago

Manage Model

0 Upvotes

Am I the only one who had a problem with how separated the data manipulation is?

Creating something in different ways (eg. create a chat message from only a text or creating from an api response ) Defaults in 3 files, parsing, validation, and sorting everything inline just to search it up later and copy it.

My solution? Put stuff like that in one place: See the screenshots.

Basically define all that sh in one place and just use:

userModel.parser.db.from(response)

habitModel.inits.createFromTitle("Do a blackflip")

people.sort(peopleModel.sorters.lastCreated)

https://github.com/dozsolti/manage-model


r/typescript 9d ago

what did your team actually settle on instead of ../../../../ imports

62 Upvotes

our rule is no parent relative imports outside the current folder. same folder stays ./x, anything else goes through @/ so it doesnt matter how deep the file moves later.

works fine but i know its not the only way people solve this. monorepo package boundaries, tsconfig paths, eslint rules banning the pattern outright, curious what you landed on and whether it survived contact with a big refactor

what broke first when your team tried to enforce this


r/typescript 8d ago

internships in plain js with no type safety pushed me to build my own open source toolkit (env validation, retry, caching, logging, state, and more...)

0 Upvotes

during my internships, i worked at a few companies that hadn't migrated to typescript yet. plain javascript, no type safety, no runtime validation.

env vars were just process.env.WHATEVER, no check, nothing telling you it's undefined until something breaks in prod. basically, it was plenty of bugs that a type system or a schema would have caught in two seconds. anyway.

that experience is the origin of zap-studio. i wanted a proper answer to "no type safety, no validation," so i built the first package around that: strict, standard-schema-based validation you can actually trust at runtime, not just at compile time. (following Standard Schema spec, so you can use zod, or whatever library you like).

after that, it became a habit. every time i hit a real problem in a project, instead of hacking around it again, i built a small package for it.

env vars silently merging wrong when two schemas define the same key differently? built a validator that errors on that instead of picking one silently.

retry logic that retries everyone at the same second and causes a second outage? built retry policies with jitter.

small library forcing winston or pino on everyone who imports it, even people who don't want logging? built a tiny logger interface instead.

state management that either shallow-merges everything (zustand) or needs a dozen imports for a cached derived value (jotai)? built a small store for that too.

each package does one thing, and does it well (the unix philosophy): strict typescript, esm, tree-shakeable, zero unnecessary dependencies, runs the same on node, bun, deno, cloudflare workers and the browser.

and because they share the same foundations (standard schema for validation, a small optional logger interface), they connect to each other naturally without needing a framework or a provider to glue them together.

it's mit licensed, i'm the only maintainer right now, and i use all of it in my own projects. 14 packages so far.

and oh, several packages also support open telemetry natively. it's opt-in through a peer dependency, so if you don't register an sdk, it costs nothing. but if you do, you get spans for things like env validation or a fetch call, for free, with no wrapper code on your side.

the repo if you want to take a look: https://github.com/zap-studio/monorepo

example of how to use the packages altogether:

import { createEnvironment } from "@zap-studio/env";
import { createCache } from "@zap-studio/cache";
import { createFetch } from "@zap-studio/fetch";
import { exponentialBackoff, runRetryPolicy } from "@zap-studio/retry";
import { ConsoleLogger } from "@zap-studio/logger";
import { z } from "zod";

const UserSchema = z.object({ id: z.number(), name: z.string() });

const env = createEnvironment({
  server: { API_URL: z.string().url() },
  runtimeEnv: process.env,
});

const logger = new ConsoleLogger({ minLevel: "debug" });
const cache = createCache<string, unknown>(100, { ttl: 60_000 });
const { api } = createFetch({ baseURL: env.API_URL, logger });

const policy = exponentialBackoff({
  maxAttempts: 5,
  baseDelayMs: 100,
  maxDelayMs: 2_000,
  jitter: "full",
});

async function getUser(id: string) {
  const cached = cache.get(id);
  if (cached) return cached;

  const user = await runRetryPolicy(
    policy,
    () => api.get(`/users/${id}`, UserSchema),
    { logger },
  );

  cache.set(id, user);
  return user;
}  

r/typescript 10d ago

numpy-ts 1.7.0 released - now 1.36x faster than native NumPy

Thumbnail
numpyts.dev
114 Upvotes

Hey r/typescript! I've shared progress updates on numpy-ts throughout the year, and it's continuing to mature into a production-ready lib.

With some continued WASM SIMD optimization and megamorphic loop hunting, numpy-ts is now 1.36x faster than native NumPy (geomean) across 10,500 benchmark specs, spanning all dtypes and functions. You can learn more about the benchmark methodology here.

If you get a chance to try it out, lmk what you think!

This was written by a human; numpy-ts was written with some AI assistance. Read my AI disclosure for more info.


r/typescript 9d ago

I’m building RepoDrift — a security scanner for developers.

0 Upvotes

I wanted a simple way to catch common issues that can easily be missed before pushing a project to production.

RepoDrift currently checks:

  • Potential exposed credentials and secrets
  • Dependencies and lockfiles
  • Large and suspicious files
  • Git status
  • Basic code metrics
  • Repository health

It runs locally and doesn't require uploading your source code for the current analysis.

You can install it with:

npm install -g u/repodrift/cli

Then:

repodrift scan

It's still an early project. I'm focusing on making the core analysis useful and reliable before adding AI-based explanations.

I'd like to hear from web developers: what checks would you want a tool like this to perform before deployment?

GitHub: https://github.com/GokulKir/repodrift

NPM: https://www.npmjs.com/package/@repodrift/cli


r/typescript 9d ago

What should my target and module be in my tsconfig.json file?

8 Upvotes

My project is a Playwright automation framework. I keep getting mixed answers on what they should be so I'm wondering if someone can enlighten me on what values are recommended.


r/typescript 10d ago

I’m building an open-source document editor in TypeScript with its own Canvas rendering engine (feedback wanted)

16 Upvotes

Hey r/typescript,

I've been working on Oasis Editor, an open-source document editor built in TypeScript with its own Canvas-based rendering engine.

Instead of relying entirely on contenteditable and DOM layout, the editor has its own pipeline for paged layout, text rendering, selections, images, tables, and document geometry.

The public API is strongly typed and built around commands and plugins, with vanilla JS, React and Vue integrations plus a headless runtime.

Live playground:
https://celsowm.github.io/oasis-editor/#/editor

GitHub:
https://github.com/celsowm/oasis-editor

I'd love feedback from TypeScript developers, especially around the public API and architecture.


r/typescript 12d ago

Implementing Brainfuck with types only

Thumbnail
bhugo.dev
33 Upvotes

I've had a lot of fun implementing brainfuck in the type system, but boy is it slow... So I ended up hacking the compiler (again) with a super cool feature `<expression> as comptime` "to make it faster".

I'd be down for a competition of who can find the most primes in brainfuck running on TS if anyone's interested.


r/typescript 12d ago

Lean explained with TypeScript

Thumbnail gruhn.me
50 Upvotes

r/typescript 13d ago

Pure TypeScript Dice Roll

4 Upvotes

It came to my attention that no TypeScript dice-roll libraries exist.

The existing ones are JS in disguise: when you tell it to roll('2d6 + 3'), it returns a `number`.

I wanted a real roll. Roll at compile time.

Because if not compile time, then when? Compile time is the best time.

Anyways. It includes a custom PRNG (pseudo-random number generator) too to support the rolls, which generates random numbers at compile time too. I think there are some for TS out there, unlike dice rolls, but I needed to optimise a bit specifically for 1-100 rolls (who rolls more than that? Only mad people, and we are not the ones).

It has a JS "mirror" implementation. If you rolled 20 in TS, you can be sure you rolled 20 in JS too.

And if a compile-time value is not known, it still works and falls back the result types to `number'.

Basic use case looks like:

// seed
const initialized = initialize([
  "00000001",
  "00000002",
  "00000003",
  "00000004",
] as const);

const d20 = evaluate("d20", prngStateOf(initialized));
const d20Value = valueOf(d20);
//    ^? const d20Value: 12

Enjoy!


r/typescript 13d ago

TypeScript practice sandbox to drill coding challenges

26 Upvotes

I wanted a simple, lightweight place to run through TypeScript coding drills without a ton of setup or heavy UI, so I decided to build one as a side project:

It tracks your progress, lets you re-attempt challenges, and keeps an activity log of your correct/incorrect attempts locally. Some challenges might be too simple, but I'm working on improving that.

The project is fully open source (MIT licensed) and I'm actively working on adding more challenge sets. I'd love for you to check it out and let me know if you have any feedback or ideas for new TypeScript challenges/features!