Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The in operator in TypeScript serves a dual purpose: it acts as a runtime type guard for control flow analysis to narrow types based on property existence, and as a compile-time iteration mechanism within mapped types to construct new object types from a union of keys.

1. Type Narrowing (Control Flow Analysis)

When used in a conditional expression, the in operator checks for the existence of a property key on an object or its prototype chain. TypeScript’s type checker intercepts this runtime operation to perform static type narrowing. Syntax:
propertyKeyExpression in objectReference
Mechanics for Union Types: If the target is a union type, TypeScript narrows the object’s type to the specific constituents that contain the property within the true branch, and excludes them in the false branch.
type TypeA = { shared: string; uniqueA: number };
type TypeB = { shared: string; uniqueB: boolean };

function evaluateUnion(target: TypeA | TypeB, key: "uniqueA") {
    if (key in target) {
        // target is statically narrowed to TypeA
        target.uniqueA; 
    } else {
        // target is statically narrowed to TypeB
        target.uniqueB; 
    }
}
Mechanics for Non-Union Types (TS 4.9+): If the target is a non-union type (such as object or unknown), the in operator narrows the type by intersecting the original type with a Record type containing the verified key. This allows safe property access for unlisted properties.
function evaluateNonUnion(target: object) {
    if ("dynamicKey" in target) {
        // target is narrowed to: object & Record<"dynamicKey", unknown>
        target.dynamicKey; 
    }
}
  • The left operand must be an expression that evaluates to a string, number, or symbol type (e.g., a string literal, or a variable of type string).
  • The right operand must be an object type or unknown.
  • Unlike discriminated unions which rely on a shared property with literal values, the in operator narrows based purely on property existence.

2. Mapped Types (Compile-Time Iteration)

Within the type system, the in keyword is used inside an index signature to iterate over a union of property keys. This allows for the programmatic generation of object types. Syntax:
type MappedType<Keys extends PropertyKey> = {
    [TypeVariable in Keys]: ValueType
}
Mechanics:
type LiteralKeys = "alpha" | "beta" | "gamma";

type GeneratedObject<T extends PropertyKey> = {
    [K in T]: K[]; 
};

type Result = GeneratedObject<LiteralKeys>;
/* 
Resolves to:
{
    alpha: "alpha"[];
    beta: "beta"[];
    gamma: "gamma"[];
}
*/
  • K acts as a type variable that binds to each constituent of the provided union (T) during iteration.
  • The in operator in this context is strictly a compile-time construct and emits no JavaScript.
  • It is exclusively used within the { [K in Union]: Type } syntax and is the foundational operator for built-in utility types like Record, Pick, and Omit.
  • It can be combined with mapping modifiers (+readonly, -?) and key remapping (as) to mutate the keys during iteration.
Master TypeScript with Deep Grasping Methodology!Learn More