Suggest an editImprove this articleRefine the answer for “What is type narrowing?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Type narrowing** is a process in which TypeScript understands exactly what type a value has in a particular branch of code, and narrows the general type down to a more specific one. **Key point:** if a variable can have several types (for example, `string | number`), TypeScript narrows that set when you perform checks like `typeof`, `in`, `instanceof`, and so on.Shown above the full answer for quick recall.Answer (EN)Image## What is **Type Narrowing** **Type narrowing** is a process in which TypeScript **understands exactly what type** a value has **in a particular branch of code** and **narrows** the general type down to a more specific one. > Put simply: > If a variable can have several types (for example, `string | number`), > TypeScript "narrows" that set when you perform checks such as `typeof`, `in`, `instanceof`, and so on. --- ## Example 1. Narrowing via `typeof` ```javascript function printId(id: string | number) { if (typeof id === "string") { // Here id: string console.log("String:", id.toUpperCase()); } else { // Here id: number console.log("Number:", id.toFixed(2)); } } ``` TypeScript understands on its own: - inside `if (typeof id === "string")` -> `id` became `string` - inside `else` -> `id` became `number` --- ## Example 2. Narrowing via `instanceof` ```javascript class User { constructor(public name: string) {} } class Admin { constructor(public name: string, public permissions: string[]) {} } function printPerson(person: User | Admin) { if (person instanceof Admin) { // Here person: Admin console.log("Permissions:", person.permissions); } else { // Here person: User console.log("Regular user:", person.name); } } ``` --- ## Example 3. Narrowing via `in` (property presence) ```javascript type User = { name: string }; type Admin = { name: string; permissions: string[] }; function printInfo(person: User | Admin) { if ("permissions" in person) { // person: Admin console.log("Permissions:", person.permissions); } else { // person: User console.log("Name:", person.name); } } ``` > `in` checks for the presence of a property, > and TypeScript uses this for logical type narrowing. --- ## Example 4. Narrowing via `==`, `===`, `!==`, `!=` TypeScript also knows how to "understand" the type after such checks: ```javascript function process(value: string | null) { if (value !== null) { // value: string console.log(value.toUpperCase()); } } ``` --- ## Example 5. Narrowing via "truthy/falsy" values TypeScript knows that `null`, `undefined`, `0`, `""`, `false` are "falsy" values. ```javascript function printName(name?: string) { if (name) { // name: string console.log("Hello,", name.toUpperCase()); } else { // name: undefined console.log("Name not provided"); } } ``` --- ## Example 6. Custom type checks (Type Guards) You can create **your own function** that helps TypeScript narrow a type: ```javascript type User = { name: string }; type Admin = { name: string; permissions: string[] }; function isAdmin(person: User | Admin): person is Admin { return "permissions" in person; } function handle(person: User | Admin) { if (isAdmin(person)) { // Here TS knows that person: Admin console.log("Permissions:", person.permissions); } else { // Here person: User console.log("User:", person.name); } } ``` > `person is Admin` is a **user-defined type guard**, > which tells TS exactly what type is returned from the check. --- ## Example 7. Narrowing inside a `switch` ```javascript type Shape = | { kind: "circle"; radius: number } | { kind: "square"; side: number } | { kind: "triangle"; base: number; height: number }; function getArea(shape: Shape): number { switch (shape.kind) { case "circle": return Math.PI * shape.radius ** 2; case "square": return shape.side ** 2; case "triangle": return (shape.base * shape.height) / 2; } } ``` > Here TypeScript uses a **discriminated union** > and automatically narrows the type in each `case` branch. --- ## Where type narrowing is used | Scenario | Example check | | --- | --- | | Primitives | `typeof value === "string"` | | Classes | `instanceof SomeClass` | | Objects | `"prop" in obj` | | Comparisons | `if (x !== null)` | | Boolean checks | `if (value)` | | Custom guard functions | `value is Type` | | switch discrimination | `case "circle": …` | --- ## Why it's needed Type narrowing lets you: - work **without errors** with union types; - get **autocomplete and hints** in the IDE; - write **safe and readable code** without unnecessary type casts (`as`). --- ### In short: > **Type narrowing** is when TypeScript "understands" > exactly what type a variable has at a given moment, > and automatically **narrows the general type** down to a specific one across different code branches.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.