-
Section 1: Getting Started
-
Section 2: Basic Types
-
Section 3: Functions and Objects
-
Section 4: Advanced Types
-
Section 5: Object-Oriented TypeScript
-
Section 6: Working with Modules
-
Section 7: Tooling and Practice
-
Section 8: Type-Level Programming
-
Section 9: TypeScript with Backends
-
Section 10: Testing Typed Code
-
Section 11: Data Validation with Types
-
Section 12: Practical Projects
-
Section 13: Compiler Internals
-
Section 14: Configuration Deep Dive
-
Section 15: Enums, Symbols, and Special Types
-
Section 16: Working with Async Code
-
Section 17: TypeScript and the DOM
-
Section 18: Advanced Generics Practice
-
Section 19: Working with Third-Party Types
-
Section 20: Monorepo and Large-Scale Practices
-
Section 21: Common Pitfalls and Best Practices
-
Section 22: Interview Practice
-
Section 23: Handbook: Narrowing In Depth
-
Section 24: Handbook: Object Types In Depth
-
Section 25: Handbook: Classes In Depth
-
Section 26: Handbook: Modules In Depth
-
Section 27: Handbook: Declaration Files In Depth
-
Section 28: JSX and Namespaces
-
Section 29: Compiler Configuration Reference
-
Section 30: More Practice Exercises
-
Section 31: Handbook: Everyday Types Deep Dive
-
Section 32: Utility Types Full Reference
-
Section 33: Decorators Reference
-
Section 34: Mixins and Advanced OOP Patterns
-
Section 35: Iterators and Generators Typing
-
Section 36: More Type-Level Programming Practice
-
Section 37: TypeScript Ecosystem Tools
-
Section 38: TypeScript with Testing Frameworks
-
Section 39: TypeScript for Library Authors
-
Section 40: More Interview Practice
-
Section 41: Handbook: Functions In Depth
-
Section 42: Handbook: Type Manipulation Deep Dive
-
Section 43: More Real-World Patterns
-
Section 44: TypeScript Release Notes Highlights
-
Section 45: Final Practice and Review
226: Common Interview Questions on Type Inference
I've sat through plenty of technical interviews where the candidate claims to "know" type inference, but then they hit a wall the moment I ask them why a specific string literal is being treated as a generic string. It's a classic trap. Many developers assume that if they assign a value to a variable, TypeScript will automatically lock that variable to the most specific type possible.
The Myth: "TypeScript always infers the most specific literal"
You might think that if you write let status = "success", TypeScript sees exactly what's happening and decides that status can only ever be the string "success". It feels intuitive. After all, the compiler sees the value right there.
let status = "success";
// You might think the type is "success"
// But TypeScript actually infers it as: string
status = "error"; // This works perfectly fine.
If TypeScript inferred the literal "success", the line status = "error" would trigger a compiler error. But it doesn't. This is because TypeScript assumes that if you're using let, you probably intend to change that value later. It "widens" the type from the specific literal "success" to the general type string to give you flexibility.
The Reality: Type Widening and the as const Escape Hatch
In an interview, the "senior" answer isn't just knowing that widening happens, but knowing how to prevent it. When you're building something like a configuration object or a set of fixed API endpoints, you don't want widening. You want the literal.
I usually recommend using as const (const assertions) when you need to tell the compiler, "I know this looks like a string, but I want you to treat it as this exact, immutable value."
const CONFIG = {
endpoint: "https://api.myapp.com",
timeout: 5000
} as const;
// Now, CONFIG.endpoint is typed as "https://api.myapp.com", NOT string.
// If you try to change it, TypeScript will throw an error because it's now readonly.
Notice the difference? By adding as const, you've changed the inference engine's behavior. This is a frequent talking point in interviews because it demonstrates you understand the trade-off between flexibility (widening) and precision (narrowing).
Handling the "Contextual Typing" Curveball
There's another side to inference that often catches people off guard: Contextual Typing. This is when TypeScript doesn't infer the type from the value (the right side), but from the location (the left side).
Take a look at this common pattern with event listeners. You don't explicitly type the event parameter, yet you get full autocomplete for event.target.
window.addEventListener("click", (event) => {
console.log(event.clientX); // TS knows this is a MouseEvent
});
I've seen candidates struggle to explain this. The trick is to realize that addEventListener is already defined in the TypeScript standard library. Because the first argument is "click", TypeScript knows that the callback function must receive a MouseEvent. It pushes the type "down" into the callback. If you were to move that arrow function to a separate variable declaration, you'd lose that inference unless you explicitly typed the variable.
📋 Practical Task
Tightening the State Machine Transition Types
You are working on a state machine for a payment flow. Currently, the transitions object is being widened to string, which is causing the updateState function to lose type safety. It's allowing any string to be passed in, even if it's not a valid state.
Your Goal: Use a const assertion to ensure the transitions object maintains its literal types, and update the updateState function to use a type derived from that object so that invalid states cause a compile-time error.
const transitions = {
IDLE: "PROCESSING",
PROCESSING: "SUCCESS",
SUCCESS: "IDLE",
ERROR: "IDLE"
};
function updateState(currentState: string) {
const nextState = transitions[currentState];
console.log(`Moving from ${currentState} to ${nextState}`);
}
// This currently works, but it SHOULD be a type error
// because "UNKNOWN" isn't a key in our transitions.
updateState("UNKNOWN");
There are no comments for now.