Types with AI A senior engineer argues that adopting strongly typed programming languages can solve problems created by AI coding assistants, including unmanageable code review volume, unmaintainable generated code, and stalled team-level projects. The author observes that LLMs excel at targeted code exploration but produce code that feels bad to review and fails to scale beyond individual productivity, while types offer a lean, reviewable description of system behavior that shifts focus to human design decisions. Types with AI 2026-07-26 I’m a big fan of types. Properly implemented, they make a system honest, safe, agile, and delightful to work in and work with. They also have incredible influence over how code gets written. Properly harnessed, they can create a pit of success 1 for engineering orgs. Unfortunately it’s incredibly hard to directly measure their benefits. It’s almost always an uphill battle to convince teams and orgs to commit to fully utilizing types. So over the past few months as AI agents are straining traditional ways of working and the industry is contorting itself to better leverage LLMs, I’ve been getting more and more excited. Maybe, finally, the need is high enough to justify broader and deeper adoption of types. Observations from the past couple months Some observations I’ve had at work and more broadly within the industry: LLMs are great at code exploration and solving targeted problems . This makes sense after seeing the current benchmarks and techniques used in post training. It’s very easy to overextend with LLMs and end up unproductive. You’ve been here before if you’ve ever felt lost working with an LLM. It’s a sign that you’ve gone beyond what you know and are no longer able to steer the LLMs out of dead ends. LLMs are bad at writing maintainable code 2 . The longitudinal aspects of maintaining a system isn’t in its training. It’s hard to encode these nonfunctional requirements as reward signals. The productivity boost from LLMs has largely not scaled beyond the individual . Team and organization level projects are still measured in the same number of weeks and months. Many LLM powered projects get to the demo phase but don’t get out . Since the beginning of 2026, I’ve seen a sharp jump in the number of new products, features, and tools developed at work. A few months have passed and almost all of them have either silently died or failed to gain adoption. Restructuring engineers into AI native pods 3 is not going well . It’s disruptive and contributing to record low morale 4 . Engineers aren’t able to keep up with the volume of code in code review . At work, we’ve experimented with several ways to keep code review alive. Most of them are some flavor of automated checks and summaries that have had the effect of reducing active participation and promoting rubber stamping. Reviewing LLM generated code feels bad. How can types help? Types have several properties that can help address and sidestep these problems. Code Review Types are a lean description of the system’s behavior. As the volume of code threatens to overwhelm code review and the provenance of the code submitted threaten to render it a meaningless ritual, types offer a way for the practice to keep up and adapt. They’re much faster to review and they shift the focus onto the structures that bound code. These structures are arguably more important than the implementation since they not only influence the current code, but also future code. As LLMs make code cheap and rote, shifting the focus of the review from the implementation to the types ensures review is focused on human design decisions and intent. It’s much more fun to review the human aspects of work. Before, code review felt personal and was a way to connect with your coworker. It was an opportunity to learn and a place to share expertise. There was an unwritten contract: the author put in time and effort and by reviewing the code you were upholding your part. Now LLM code reflects nothing about your coworker — there’s nothing to learn from reading it line by line. The effort to wade into the slop to find something interesting to remark on isn’t rewarding. Who’s the feedback for? Your coworker isn’t writing code anymore and your comments aren’t directly driving improvements to the models. And worst of all, it’s no longer certain your coworkers are even reviewing their own code anymore. Whenever I review code, I jump directly to the types. If they don’t exist, I look at function signatures to understand the interfaces. This offers me a hierarchical map that allows me to jump around and dive in and out of implementation to find anything interesting or critical. I realized that going into the code is slow and doesn’t matter if the original design was flawed. Types offer a quick short circuit check with a fraction of the reading. Summaries can be another alternative but they’re often misleading, outdated, or omit key details. Increasingly, they’re being written by AI which often misprioritize or highlight nonsensical details that further obfuscates what the purpose of the change is. At one point, we also looked to prompts as an alternative. While they offer exact insight to the author’s intent, they pose a huge privacy issue. Most people are uncomfortable or unwilling to have their prompts inspected. In practice, reviewing prompts is also awkward as most work gets done in multiple turns. Critically, both options contain a fatal flaw. Neither are guaranteed to be true to the implementation. Misleading differences exist all the time. Types, on the other hand, are part of the implementation so they’re guaranteed to be true. Communication with LLMs Types are specific , I’ve observed that overextending is often how I get lost and end up unproductive. It’s very easy to underspecify with English. To be fair, English works just fine and is often the best approach to prompt LLMs for trivial problems. But as problems get more complex, prose is just not specific enough. Expressing all the technical details required for a complex problem in plain English is not natural. It requires a prohibitively high amount of effort. In practice, what usually happens is we under-specify. English happily allows us to gloss over gaps and go beyond what we know, and get into a situation where we’re unable to inspect and audit the output. Types keep you honest. Types force you to explore and answer critical questions to just describe the problem. Mental gaps are highlighted, complex ideas have to be hierarchically built from primitives. This way of working is a more conservative approach to vibe coding and requires more effort. The role of LLMs in this model of working is explorer and implementer, and less so of a designer. My experience is that this model of working is much more sustainable in real code bases where the output code has to continue to live and be iterated on. Types are easily auditable. It took the recent capacity crunch at Anthropic for me to realize that English can be quite unreadable. For a few weeks in May and June, I noticed Claude’s output was extremely hard to read because of how terse and dense it was. I assume this was some internal dial the Anthropic team turned up to save on inference. But even before this, my eyes were already glazing over when reading LLM output. They can be quite repetitive, verbose, and misprioritized. So whenever appropriate, I force its output to be in types. It’s a much easier format to audit. I’m able to scan and jump around instead of reading a block of text sequentially. This is especially helpful when I’m onboarding to new code. LLMs are much better than me at exploring. One of the tasks I often put them through is to explore a codebase and then describe the domain to me by writing out a temporary type file. Communication with People Outside of code review, types give names to complex ideas and allow them to enter regular discussions without the need for an open code editor. Like jargon in any specialized setting, a shared technical vocabulary allows an organization to collectively increase the level of specificity and technicality in which it can communicate. This can have massive second order effects in how efficiently an organization can operate. I’ve had many meetings where the reason was because someone had a wrong premise or question that could have been corrected or answered if they were able to communicate more specifically about what they were after. Splitting Work A formative project I worked on involved rolling out a fleet of microservices forming a federated GraphQL layer at Chegg. It was more complex and less computationally efficient than the monolith that preceded it, but allowed disparate teams across time zones to collaborate on the same product and make collective and cohesive improvements. The federated schema was the backbone that made this possible. It allowed us to partition the system and split up work so each team had ownership and freedom within their domain but guaranteed that their work fit back together. The bottlenecks I’m observing at the moment seem to be mostly at the boundaries where collaboration is needed. There’s a significant slowdown along these seams that prevent individual productivity from multiplying to move larger projects forward. Could a similar strategy in partitioning work create the freedom and agency in which LLM development thrives, and also constrain it to make forward progress for the organization? Maybe. It’d certainly be less disruptive to employees than uprooting and reorganizing them into pods. There’s also only so many independent products or greenfield projects that can spin up; splitting up work into independent pieces without addressing coordination seems doomed. It’s possible that these pods all go fast but in opposite directions. Building Sustainably Types compose and extend , creating natural paths for low entropy growth. They provide an index of the built system, name its reusable building blocks, and surface its natural extension points. By default, LLMs aren’t very good at building like this. They’re reinforced to perform very well in constrained and point-in-time tasks. Operating on types allows LLMs and organizations to easily identify the best ways to grow, rather than the most convenient. Unsurprisingly, this type of growth keeps the system agile. It minimizes sprawl and accumulates operational leverage; the system remains cohesive and easy to understand and big changes stay simple and safe. Operating on types In practice, what would leaning on these properties and fully utilizing types look like? Broadly, I think it means shifting human contribution up to the level of types and delegating more of the implementation to LLMs, through types. A few things I’m more confident will happen are: - Types would be a first class part of software development. They’d be able to exist standalone from code and discoverable and accessible, with processes currently centered around code re-centered around types. - Code becomes commoditized, fungible, and blackboxed. - Software engineering becomes less about writing code and more about modeling systems and describing its requirements and expected behavior. - LLMs usage becomes intentional and bifurcated into exploration and execution. In this paradigm, the human contribution is at the point of highest leverage, and complement the weaknesses of LLMs: decision making, contextualizing business requirements, and anticipating future requirements. It’s a more conservative approach to working with LLMs but I don’t think it’s possible to do better. As much as the marketing would like you to believe that autonomous agents are coming, I don’t see how it could ever be possible. The gaps remaining are really just about clarity of requirements and taste. These are unbridgeable unless agents are able to read minds. References 1 https://blog.codinghorror.com/falling-into-the-pit-of-success/ 2 https://arxiv.org/abs/2603.24755 3 https://www.businessinsider.com/metas-reality-labs-shifts-to-ai-native-pods-efficiency-2026-3 4 https://www.wired.com/story/mark-zuckerberg-meta-employee-meeting-interrupt-ai/