Which model actually writes better TypeScript, and does it matter enough to change what you reach for? I ran Claude Fable 5 and GPT-4o through the same set of TypeScript generation tasks to find out, and the answer is more useful than a leaderboard number: each model has a different failure mode, and which one bites you depends on what you are building.
I do a fair amount of AI systems architecture work, and picking the right model for codegen inside a pipeline is a decision that compounds. Get it wrong and you are paying for review time on every generated PR. Here is what actually held up under test.
I kept the test as fair as I could make it. Both models got the same prompts, the same grading rubric, and no retries. The rubric had three gates:
strict: true
in tsconfig without new errors.Each task was a well defined, realistic TypeScript problem: shaping a typed API response, modeling a tagged union for a state machine, and writing an async function with proper error boundaries. I ran every prompt through both models and scored the output against the rubric, so any difference in output is attributable to the model, not to the prompt or the grading.
| Test dimension | What I checked |
|---|---|
| Compiles clean | Zero manual fixes needed |
| Strict mode | No new errors under strict: true |
| Error handling | No silent unhandled rejections |
| Schema validation | Runtime safety at the API boundary, not just compile time types |
Both models are competent at basic type inference, but they trip up in different spots once things get less trivial.
Claude Fable 5 is generally stronger with generics and utility types, and it tends to produce output that survives strict mode without hand holding. Where it struggles more is deeply nested discriminated unions. It occasionally misses an edge case in the union or narrows a branch incorrectly, so you still want a human pass on anything with more than two or three variants.
GPT-4o is consistent on simple and intermediate inference, but it is more likely to fall over on advanced patterns like conditional types or heavily generic utility helpers. Here is a discriminated union pattern that is a decent stress test for either model:
type RequestState<T> =
| { status: "idle" }
| { status: "" }
| { status: "success"; data: T }
| { status: "error"; message: string };
function render<T>(state: RequestState<T>): string {
switch (state.status) {
case "idle":
return "Waiting to start";
case "":
return "";
case "success":
return `Loaded: ${JSON.stringify(state.data)}`;
case "error":
return `Failed: ${state.message}`;
}
}
If a model drops the exhaustiveness check on that switch
, strict mode will not catch a missing case unless you add a never
assertion at the end. That is exactly the kind of thing I check for by hand, because both models occasionally skip it.
This is where the gap is most visible in day to day generated code. Claude Fable 5 is more thorough about wrapping awaited calls in try or catch and tends to type the error branch instead of leaving it as any
or unknown
without narrowing. GPT-4o is fine on the common path but more likely to leave a promise chain that can reject without a handler, especially inside Promise.all
calls or event callbacks.
A pattern I now check for explicitly in any generated async code:
async function fetchUser(id: string): Promise<User> {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) {
throw new Error(`Request failed with status ${res.status}`);
}
return (await res.json()) as User;
} catch (err) {
if (err instanceof Error) {
throw new Error(`fetchUser failed: ${err.message}`);
}
throw new Error("fetchUser failed with an unknown error");
}
}
Small thing, but the err instanceof Error
narrowing before you touch .message
is exactly the kind of detail that gets skipped under a fast generation pass. Review for it either way, but expect to catch it more often in GPT-4o output.
Structured tool calling with Zod schema validation is the production standard for LLM apps right now, and this is a category where the SDK you wire the model into matters as much as the model itself. If you want the fuller picture on picking models for agentic pipelines, I go deeper in this LLM comparison for agentic AI.
On raw schema generation, Claude Fable 5 tends to produce Zod schemas that are stricter by default, catching optional versus required fields correctly more often. GPT-4o's schemas are usable but more often need a manual tightening pass, particularly around nullable fields.
import { z } from "zod";
const ToolInput = z.object({
query: z.string().min(1),
maxResults: z.number().int().positive().max(50).default(10),
filters: z
.object({
category: z.enum(["docs", "code", "issues"]).optional(),
})
.optional(),
});
type ToolInput = z.infer<typeof ToolInput>;
One footprint note worth knowing before you pick your SDK layer: the Vercel AI SDK is 67.5kB gzipped versus the OpenAI SDK at 34.3kB, with LangChain JS coming in heaviest at 101.2kB. If bundle size matters for your deployment target, that is a real tradeoff independent of which model you are calling through it.
I do not have clean head to head pricing for the full Claude Fable 5 and GPT-4o tiers, so I will not fake precision there. What I can say with real numbers: at the smaller tiers, GPT-4o-mini runs about $0.15 per 1M input tokens, while Claude Haiku runs closer to $0.80 per 1M input tokens. That gap matters once you are running codegen at scale across a CI pipeline instead of a one off request.
The broader trend helps regardless of which model you land on. LLM prices dropped roughly 80 percent between early 2025 and early 2026, so the cost conversation looks very different than it did two years ago. Cost sensitive teams running high volume, low complexity generation are in a much better spot than they used to be, even on the pricier tier.
| Tier | Approx input cost per 1M tokens |
|---|---|
| GPT-4o-mini | $0.15 |
| Claude Haiku | $0.80 |
I will take an actual position instead of hedging. If you are prototyping, doing cost sensitive high volume generation, or the output is going to get a human review pass anyway, GPT-4o is the practical default. It is cheaper at the mini tier and good enough for common patterns.
If you are generating code that ships closer to production with less review, especially anything involving nested unions, async error paths, or Zod schemas at an API boundary, Claude Fable 5 is worth the extra cost. It fails less often in the places that are expensive to catch in code review, which is where the real cost of a codegen pipeline actually lives.
Neither is the universally correct pick. Match the model to how much human review sits between the generated code and production.
Is Claude better than GPT-4 for TypeScript?
For strict mode compliance and safer async error handling, Claude Fable 5 comes out ahead in this test. GPT-4o is close on common patterns and cheaper at the mini tier, so the better choice depends on your review process and budget.
Which LLM writes the best TypeScript code?
In this comparison, Claude Fable 5 produced more reliable output on discriminated unions, async error handling, and Zod schema generation. GPT-4o is a solid, cheaper option for simpler generation tasks.
How does Claude Fable 5 compare to GPT-4o for developers?
Claude Fable 5 needs less manual cleanup on complex type patterns and error handling, which matters if less human review sits between generation and production. GPT-4o remains a strong, more budget friendly option for prototyping and simpler codegen work.
If you want a deeper look at picking models for production pipelines, I cover it in more detail on my site.
If you want this wired up on your own site end to end, that is exactly the kind of work I take on.
Drop a comment if your setup looks different — curious what variations people are running in production.