Skip to content
Journal

Business · Hiring

How to Hire a TypeScript Developer in 2026: Separating Real Skill From a Type Annotation

TypeScript is now the default for most web projects, which means the market is full of developers who write TypeScript without understanding it. Here is how to tell them apart.

Prathviraj Singh

Prathviraj Singh

7 min read

How to Hire a TypeScript Developer in 2026: Separating Real Skill From a Type Annotation

Sponsored

Share

TypeScript became the default language for new web projects somewhere around 2022. By 2026, claiming TypeScript on a resume is closer to claiming JavaScript than it is to claiming a specialization. Almost everyone who builds for the web has touched it. Most have not learned it.

This creates a genuinely hard hiring problem. The resumes all look the same. The candidates all say yes when you ask if they know TypeScript. The gap only surfaces during onboarding, when you discover someone has been using as any as their primary debugging strategy.

Your screen has to do the disambiguation work.

What “using TypeScript” actually covers

Before writing interview questions, it helps to name what you are distinguishing between.

Level 1 — Annotated JavaScript. The developer adds : string, : number, and interface MyData { ... } where VSCode complains. They reach for as any when the type checker says something they do not understand. They have "strict": false in their tsconfig because they turned it off when it gave them errors they could not immediately fix. Their TypeScript code works, but would be identical in behavior without the types.

Level 2 — Informed TypeScript. The developer understands strict mode, writes types that actually constrain their code, and can use generics for simple utilities. They know the difference between interface and type (and when it matters). They do not use any without thinking about it. They can read and modify existing type definitions. This is the baseline for most mid-level TypeScript roles.

Level 3 — TypeScript as design tool. The developer uses the type system to model domain problems. They write discriminated unions to make illegal states unrepresentable. They use conditional types and mapped types when they simplify the codebase. They understand never and use it in exhaustive checks. They choose between unknown and any deliberately. They contribute to the project’s type infrastructure, not just consume it. This is what you need for senior frontend engineers, full-stack TypeScript leads, and anyone building reusable libraries or frameworks.

Most job descriptions want Level 3. Most resumes describe Level 1.

The questions that reveal which level you are hiring

Generic function constraints

Ask the candidate to write a function that accepts an array of objects and returns the values at a given key, with the return type inferred correctly.

A Level 1 response writes function pluck(arr: any[], key: string): any[].

A Level 2 response writes function pluck<T>(arr: T[], key: keyof T): T[keyof T][].

A Level 3 response gets there and then asks: do you want to constrain K to a specific key of T? They write function pluck<T, K extends keyof T>(arr: T[], key: K): T[K][] and explain why K extends keyof T is better than key: keyof T for inference.

That difference shows you whether they understand type-level computation or just syntax.

Discriminated unions and exhaustive handling

Give them this problem:

type LoadState =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };

function render(state: LoadState): string {
  // implement this
}

Ask them to implement render and explain what happens if you add a new variant to LoadState later.

Level 1: They use if (state.status === "success") chains but forget the never check and cannot explain what happens with new variants.

Level 2: They handle all four cases correctly and mention that the compiler will error on new unhandled variants.

Level 3: They write the exhaustive check explicitly:

function assertNever(x: never): never {
  throw new Error(`Unhandled case: ${JSON.stringify(x)}`);
}

And explain that this catches missing cases at both compile time and runtime. They will likely mention that this pattern is how React’s reducer state works under the hood.

The unknown vs any question

Ask: “When would you use unknown instead of any, and why?”

A failing answer: “They are basically the same but unknown is safer.”

A passing answer: “unknown forces you to narrow the type before you can do anything with it. any turns off type checking entirely. I use unknown for values coming from outside TypeScript’s control — API responses, try/catch error values, anything deserialized from JSON — and then narrow it explicitly. any I treat as a code smell. If I reach for it, I am usually making a mistake.”

The best answers also mention that error in catch blocks is typed as unknown in strict mode, which is correct behavior — you do not know what was thrown.

tsconfig walkthrough

Ask the candidate to open a blank tsconfig and walk you through what they set for a new project.

They should, without prompting: enable strict, mention what strictNullChecks buys you, address moduleResolution (Node16 or Bundler for modern projects), and say something about target and lib.

If they set "strict": false, ask them why. “It was throwing too many errors” is the answer that tells you most of what you need to know.

The take-home task

For mid-level and senior candidates, a short take-home is more reliable than any interview question.

The task:

Model a payment processing system. A payment can be in one of five states: pending, processing, completed, failed, or refunded. A completed payment has an amount and a transaction ID. A failed payment has an error code and a message. A refunded payment has an amount, a transaction ID, and a refund timestamp.

  1. Model this with TypeScript types.
  2. Write a function summarizePayment(payment: Payment): string that returns a human-readable summary for each state. It must not compile if a new state is added without handling it.
  3. Write a function getTotalSuccessAmount(payments: Payment[]): number that sums completed amounts.

Expected time: 45-60 minutes. There is no UI. The deliverable is a TypeScript file with no as any and no @ts-ignore.

What you’re looking for: discriminated union with literal type tags, explicit never exhaustiveness guard, correct inference of narrowed types inside each branch, and type-safe extraction of optional fields. Bonus points if they add a comment explaining why the exhaustiveness check matters.

Framework-specific questions

TypeScript skill overlaps significantly with framework choice. If you are hiring for a specific stack, add one framework-specific round.

Next.js: Ask about server component types — how params and searchParams are typed in the App Router, and why the async nature of server components changed their type signatures in Next.js 15. A developer who does not know this has not built with the App Router in production.

NestJS: Ask about decorator metadata types, the role of @Injectable() in the type system, and how DTOs validated with class-validator interact with TypeScript’s structural typing. This is a complex enough intersection that surface-level TypeScript knowledge will not get through it.

tRPC: Ask how the type inference chain from server router to client works, and how to type a context object that is built in middleware. Understanding this requires a genuine grasp of TypeScript generics at the library level.

How the hiring cluster connects

The TypeScript screen is part of a larger process. Technical interview design covers the structural framework. How to hire a full-stack developer handles the broader role definition. For rates, what it costs to hire a developer in 2026 has current market ranges.

For TypeScript specifically, expect to pay a meaningful premium over a generic JavaScript developer for someone who reaches Level 3. The skill is genuinely rare. Most TypeScript developers are Level 1 developers with a TypeScript section on their resume.

The take-home task described above filters for Level 2 and above. The discriminated union and exhaustiveness questions push to Level 3. Between them, you will not waste six months discovering the difference on the job.

If you would rather skip the search, codercops screens TypeScript developers and hands you a vetted shortlist. See available TypeScript developers on codercops and post your role to get matched.

Frequently asked questions

What TypeScript concepts should I actually test in a hiring screen?
Focus on: generic functions and constraints (not just `<T>` but `<T extends Something>`), discriminated unions for modeling state, type narrowing with `in`, `typeof`, and `instanceof`, mapped types for transformations, and the `unknown` vs `any` distinction. These are the features that show up constantly in production TypeScript and separate developers who understand the system from those who treat it as annotated JavaScript.
What is the difference between a TypeScript developer and a JavaScript developer who uses TypeScript?
A TypeScript developer uses the type system to catch errors at compile time, model domain state, and make impossible states unrepresentable. They write types that express business logic. A JavaScript developer who uses TypeScript adds annotations where required, works around the type checker with `as any` when it gets in the way, and turns off strict mode when it complains. The former prevents bugs. The latter just makes the code harder to read.
Should I require TypeScript for backend roles, not just frontend?
Yes, for any Node.js or Bun-based backend. The ecosystem has moved: Prisma, Drizzle, Fastify, NestJS, Hono, and tRPC are all TypeScript-first. A backend developer who does not know TypeScript will slow down a modern Node.js codebase almost immediately. The one exception is Go or Rust backends, where TypeScript knowledge is irrelevant.
How do I screen for good tsconfig.json choices?
Ask the candidate to walk you through their default tsconfig for a new project and explain why they set each flag. A strong answer includes: `strict: true` as the baseline, an explanation of what `strictNullChecks` and `noImplicitAny` actually enforce, and a mention of `moduleResolution` being relevant for ESM compatibility. If they copy a tsconfig from StackOverflow without being able to explain it, they will create configuration debt.
What TypeScript red flags should I watch for?
Using `as any` to silence the compiler (more than rarely), writing return type annotations everywhere instead of letting inference work (over-annotation suggests they do not trust the system), generic functions that use `T` without constraints (usually means they copied a pattern without understanding it), and an inability to explain what `never` is for. Also watch for candidates who describe TypeScript purely as 'catching typos' — that framing understates what the type system actually does.

Sources

Sponsored

Sponsored

Discussion

Join the conversation.

Comments are powered by GitHub Discussions. Sign in with your GitHub account to leave a comment.

Sponsored