The brief said “senior TypeScript developer, product team, fast-moving environment”. What the role actually involved was becoming the only living person who understood a four-year-old codebase whose three original authors had all left. We hired a genuinely excellent engineer and they were miserable within six weeks, because we had described the wrong job.
Why a takeover is a different hire
A feature hire is judged on how well they add to a system somebody can explain to them. A takeover hire is judged on how well they operate when nobody can explain anything at all. Those are different skills, and very often different people.
The takeover candidate has to be comfortable reading far more code than they write for the first two months. They have to be willing to leave working-but-ugly code alone. And they have to make forward progress without the context that normally makes engineering decisions feel safe.
Strong feature developers frequently struggle here, and it is worth understanding why, because it is not a deficiency. The instinct that makes them effective — see something wrong, fix it properly — is precisely the instinct that wrecks an inherited system in month one, when “wrong” often turns out to be an undocumented business rule that someone will notice at quarter end.
Singapore adds a specific wrinkle. This is a market with a high concentration of regional headquarters and a lot of engineering work that was originally built elsewhere and then transferred here. A meaningful share of TypeScript roles in this market are takeovers described as feature roles, and the mismatch is usually discovered by the new hire rather than by the hiring manager.
The mistake I made
We optimised the loop for the wrong thing. Our interview was a well-designed algorithmic exercise plus a system design round, and it selected, correctly, for someone who could build. Nothing in it asked whether the candidate could sit with an unfamiliar four-thousand-line module and resist the urge to improve it. Six weeks in, we had a beautifully refactored authentication layer, two regressions in billing, and an engineer who felt set up to fail. That was our fault entirely, and it was fixable at the job-description stage for free.
Check 1 — Audit your own strictness before you write the brief
Open tsconfig.json and find out what you are actually asking someone to own. Is strict on? Is noImplicitAny on? How many files are excluded from checking altogether? Then count occurrences of any and of @ts-ignore across the repository.
This takes about twenty minutes and it changes the role materially. A fully strict codebase gives a new owner a compiler that answers questions for them. A codebase with strict disabled and a few hundred escape hatches gives them nothing but text, and the job is closer to archaeology than to engineering.
Both are legitimate roles to hire for. They are not the same role, they do not attract the same candidate, and they should not carry the same expectations about month-one output.
Check 2 — Measure the real test surface, not the coverage number
Coverage percentage is close to meaningless here. A codebase at 80% coverage where every test asserts that a function returns without throwing offers no safety at all.
Ask the more useful question: if someone changes this incorrectly, does anything catch it before production? Work through your two or three most business-critical paths — billing, authentication, whatever loses money when it breaks — and establish honestly whether a wrong change is caught.
Where the answer is no, you have not just found a testing gap. You have found the part of the job where a new owner will be slowest, most cautious and most in need of support, and you should say so in the interview rather than discovering it together in week five.
Not sure whether you are hiring a feature developer or a takeover?
We audit the codebase first — strictness, real test surface, dependency risk — then write the brief that matches the job you actually have.
Let us look at it with youCheck 3 — Write the brief as a takeover, not as a feature role
This is where most of the value in this article sits, and it costs nothing.
Say plainly in the posting that the codebase was written by people who have left. State its approximate age and size. Describe the first ninety days as stabilisation rather than delivery. Name the framework versions honestly, including the ones that are behind.
Hiring managers resist this because it reads as a warning label. It is a warning label, and that is exactly why it works. It repels candidates who want a greenfield product role — who would have resigned in month three anyway — and it strongly attracts a specific type of engineer who genuinely enjoys this work and is tired of discovering the truth after signing.
The honest brief also does something subtler. It tells a good candidate that you understand your own situation, which is a meaningful signal in a market where most postings do not.
Check 4 — Run the archaeology interview on your real code
Replace one interview round with this. Take a genuine file from your repository — 200 to 400 lines, moderately messy, ideally something with an undocumented business rule in it — and give it to the candidate with fifteen minutes to read.
Then ask three questions:
- What does this do? You are testing reading comprehension of unfamiliar code, which is the actual daily activity of the role.
- What worries you about it? You are testing risk instinct.
- What would you not touch in your first month, and why? This is the question that matters most.
The weak answer to the third question is an enthusiastic rewrite plan delivered inside two minutes. The strong answer identifies what is dangerous, explicitly defers the things whose purpose is unclear, and asks you questions about business behaviour that the code cannot reveal. That combination — restraint plus curiosity about intent — predicts success here better than any algorithmic exercise I have used.
Check 5 — Test the type-narrowing skill explicitly
Most inherited TypeScript work is not writing new types. It is tightening existing ones without changing runtime behaviour, incrementally, in a codebase that is still shipping.
Ask directly: there is an any in a function called from forty places — how do you remove it?
Listen for a staged approach. Strong candidates talk about narrowing at the boundary first, introducing a type and letting the compiler enumerate the call sites, fixing them in small reviewable batches, and using unknown with explicit narrowing as an intermediate step rather than jumping straight to a concrete type. Weak candidates propose a single large change and assume the tests will catch problems — which, per check two, they very likely will not.
Check 6 — Check dependency and runtime archaeology
Inherited codebases carry inherited dependencies, and this is where genuinely dangerous work hides. Ask how the candidate would approach an unmaintained package pinned three major versions behind, still used in a critical path.
You are looking for a staged plan with a rollback: assess what actually breaks, find the smallest reversible step, verify behaviour before and after. You are listening against two failure modes — upgrade everything immediately, and never touch it — both of which are common and both of which are wrong.
Ask the same question about the build. Inherited projects routinely have a build process that only worked on a departed engineer’s machine, and a candidate who has been through that before will recognise the situation from the description alone.
Check 7 — Define the first ninety days as measurable stabilisation
Write this down before the offer goes out, and share it with the candidate during the process.
- Month one: a documented build and deploy path that a second person can follow. No new features. None.
- Month two: the strictness dial moved one notch — one flag enabled, or one excluded directory brought under checking — plus tests around the two riskiest paths from check two.
- Month three: first feature delivered through the now-documented path, with the new owner writing the plan rather than following one.
The single most common way to ruin a takeover hire is to expect feature delivery in month one. It pushes a careful engineer into shipping changes to code they do not understand yet, which produces exactly the regressions you hired them to prevent. Give them explicit permission to stabilise, with deliverables specific enough that “stabilising” never looks like drifting.
If the audit in checks one and two suggests the work is larger than one person can absorb, the honest conclusion may be that you need a small team rather than a hire — the structure for that is covered in our note on enterprise software delivery in Singapore, and the cost side in our current engineering rate breakdown. If it is a single hire, start from hiring developers into an existing team. We see the same takeover pattern in the Gulf, where our Dubai engineering practice handles a high volume of transferred codebases for the same regional-headquarters reason.
Frequently asked questions
How is hiring for an inherited TypeScript codebase different from a normal developer hire?
A feature hire is assessed on how well they add to a system whose conventions someone can explain to them. A takeover hire is assessed on how well they operate when nobody can explain anything, which is a different skill and frequently a different person. The takeover candidate needs to be comfortable reading far more code than they write, to be willing to leave working-but-ugly code alone, and to make progress without the context that normally makes engineering decisions feel safe. Strong feature developers routinely struggle with this, because the instinct that makes them effective — rewrite it properly — is the instinct that destroys an inherited system in month one.
Should we require experience with our exact framework version?
Usually not, and this requirement narrows Singapore shortlists badly for very little gain. A developer who has taken over two unfamiliar codebases successfully will learn your framework version in a fortnight. A developer who knows your exact stack but has only ever worked on code they wrote themselves will still struggle with the parts that actually make a takeover hard: undocumented business rules, dead code that looks live, and a build process nobody understands. Filter on demonstrated takeover experience first and treat framework familiarity as a secondary preference, not a gate.
What is the single strongest interview signal for a takeover role?
Restraint under uncertainty. When you give a candidate a real file from your repository and ask what they would change, the weak answer is an enthusiastic rewrite plan delivered within two minutes. The strong answer identifies what is risky, states what they would deliberately not touch until they understand it, and asks you questions about business behaviour the code cannot reveal. That combination — willingness to leave working code alone plus active curiosity about intent — predicts success in an inherited codebase better than any algorithmic exercise, and it takes twenty minutes to assess.
How long before a takeover hire is genuinely productive?
Plan for meaningful but unglamorous output within four to six weeks, and full feature velocity somewhere between three and four months, scaled by how much of the codebase is type-checked and tested. The mistake that ruins these hires is expecting feature delivery in month one, which pushes a careful engineer into shipping changes to code they do not yet understand. Define the first ninety days as stabilisation with measurable deliverables — a documented deploy path, one notch of extra type strictness, tests around the two riskiest paths — and you will get both the stabilisation and, shortly afterwards, the velocity.
Hiring a TypeScript developer to own an inherited codebase?
We screen for takeover ability rather than feature velocity — archaeology, restraint, incremental type narrowing — and put vetted Singapore-based candidates in front of you.
Start — see vetted TypeScript engineers