How to fix Type parameter for mapped type must be 'in' expression in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 11, 2025· 93 views

This TypeScript error occurs when creating mapped types with incorrect syntax. Mapped types require the "in" keyword to iterate over union types, and this error appears when the type parameter is missing or malformed. The fix involves correcting the mapped type syntax to use proper "key in Type" pattern.

Quick fix

Fixes Type parameter for mapped type must be 'in' expression

// WRONG - missing 'in'
type Partial<T> = {
  [K]?: T[K];  // Error: Type parameter for mapped type must be 'in' expression
};

// CORRECT - add 'in'
type Partial<T> = {
  [K in keyof T]?: T[K];  // ✓ Correct syntax
};

// Another example:
// WRONG
type ReadonlyProps<T> = {
  [P]: T[P];  // Error
};

// CORRECT
type ReadonlyProps<T> = {
  readonly [P in keyof T]: T[P];  // ✓
};
  1. Add the missing "in" keyword to your mapped type
  2. Fix typos in the "in" keyword
  3. Use proper key types with the "in" operator
  4. Distinguish mapped types from index signatures
typescript — error
// WRONG - missing 'in'
type Partial<T> = {
[K]?: T[K]; // Error: Type parameter for mapped type must be 'in' expression
};
// CORRECT - add 'in'
type Partial<T> = {
[K in keyof T]?: T[K]; // ✓ Correct syntax
};
// Another example:
// WRONG
type ReadonlyProps<T> = {
[P]: T[P]; // Error
};
// CORRECT
type ReadonlyProps<T> = {
readonly [P in keyof T]: T[P]; // ✓
};
Type parameter for mapped type must be 'in' expression

What this error means

The "Type parameter for mapped type must be 'in' expression" error occurs when TypeScript encounters invalid syntax in a mapped type declaration. Mapped types are a powerful TypeScript feature that allows you to create new types by transforming properties of existing types. In TypeScript, mapped types use the syntax `{[K in KeyType]: ValueType}` where `K` is a type variable that iterates over each member of `KeyType` (typically a union type). The `in` keyword is required to specify that you're mapping over the keys. This error typically appears when: 1. You forget the `in` keyword entirely 2. You use incorrect syntax like `{[K]: ValueType}` without `in` 3. You have a typo or misplaced syntax in the type parameter 4. You're trying to use a conditional type or other expression where mapped type syntax is expected The error prevents compilation because TypeScript cannot parse the mapped type declaration correctly.

Typical symptoms

  • TypeScript compilation fails with "Type parameter for mapped type must be 'in' expression"
  • IDE shows red underlines on mapped type declarations
  • Error appears when defining utility types like Partial, Readonly, or custom mapped types
  • Code fails to compile but the syntax looks visually similar to correct mapped types
  • Error occurs in .ts or .tsx files when using advanced type transformations

Common causes

  1. Missing the "in" keyword in mapped type syntax: using {[K]: T} instead of {[K in Keys]: T}
  2. Typo in the "in" keyword (e.g., "inn", "on", or missing space)
  3. Using incorrect syntax for key iteration like {[K of Keys]: T}
  4. Attempting to use conditional type syntax within mapped type brackets
  5. Confusing mapped types with index signatures which use different syntax
  6. Nested type errors where the key type itself has syntax issues
  7. Using reserved keywords or invalid identifiers as the type parameter name

How to fix "Type parameter for mapped type must be 'in' expression"

1Add the missing "in" keyword to your mapped type

The most common fix is to add the in keyword between the type parameter and the key type:

typescript
// WRONG - missing 'in'
type Partial<T> = {
  [K]?: T[K];  // Error: Type parameter for mapped type must be 'in' expression
};

// CORRECT - add 'in'
type Partial<T> = {
  [K in keyof T]?: T[K];  // ✓ Correct syntax
};

// Another example:
// WRONG
type ReadonlyProps<T> = {
  [P]: T[P];  // Error
};

// CORRECT
type ReadonlyProps<T> = {
  readonly [P in keyof T]: T[P];  // ✓
};

The basic pattern is always: {[TypeParameter in KeyType]: ValueType}

2Fix typos in the "in" keyword

Ensure you're using exactly in (lowercase, two letters):

typescript
// WRONG - typo
type Mapped<T> = {
  [K inn keyof T]: T[K];  // 'inn' instead of 'in'
};

// WRONG - uppercase
type Mapped<T> = {
  [K IN keyof T]: T[K];  // 'IN' instead of 'in'
};

// WRONG - wrong keyword
type Mapped<T> = {
  [K of keyof T]: T[K];  // 'of' instead of 'in'
};

// CORRECT
type Mapped<T> = {
  [K in keyof T]: T[K];  // ✓
};

Also check for missing spaces:

typescript
// WRONG - missing space
type Mapped<T> = {[K inkeyof T]: T[K]};  // 'inkeyof' should be 'in keyof'

// CORRECT
type Mapped<T> = {[K in keyof T]: T[K]};  // ✓ Space after 'in'
3Use proper key types with the "in" operator

The type after in must be a valid key type (typically a union type or keyof expression):

typescript
// WRONG - using a type that isn't valid for iteration
type Colors = 'red' | 'green' | 'blue';
type ColorValues = {
  [C in Colors]: string;  // ✓ This is actually correct!
};

// WRONG - trying to iterate over non-union type
type BadExample = {
  [K in string]: any;  // Error: string is too broad for mapped types
};

// CORRECT - use keyof to get keys from an object type
interface User {
  id: number;
  name: string;
  email: string;
}

type OptionalUser = {
  [K in keyof User]?: User[K];  // ✓ Makes all properties optional
};

// CORRECT - iterate over literal union
type Status = 'pending' | 'success' | 'error';
type StatusMap = {
  [S in Status]: boolean;  // ✓ Creates {pending: boolean, success: boolean, error: boolean}
};

Common valid key types:
- keyof T (keys of an object type)
- Union of string literals: 'a' | 'b' | 'c'
- Template literal types (TypeScript 4.1+)

4Distinguish mapped types from index signatures

Don't confuse mapped types with index signatures. They have different syntax:

typescript
// INDEX SIGNATURE (not a mapped type)
interface StringDictionary {
  [key: string]: string;  // ✓ No 'in', just [key: type]: valueType
}

// MAPPED TYPE (requires 'in')
type ReadonlyDictionary<T> = {
  readonly [K in keyof T]: T[K];  // ✓ Uses 'in' keyword
};

// WRONG - mixing syntax
type ConfusedType = {
  [key: keyof T]: T[key];  // Error: Should be [K in keyof T]: T[K]
};

// CORRECT - choose one pattern
// Option 1: Index signature (all string keys)
type StringIndex = {
  [key: string]: number;
};

// Option 2: Mapped type (specific keys)
type SpecificKeys = {
  [K in 'x' | 'y' | 'z']: number;
};

Use index signatures when you want all possible string/number keys.
Use mapped types when you want to transform specific known keys.

5Check for nested syntax errors in complex types

In complex type definitions, the error might be in a nested position:

typescript
// WRONG - error in nested mapped type
type DeepMapped<T> = {
  [K in keyof T]: {
    [P]: T[K][P];  // Error here! Missing 'in' in nested mapped type
  };
};

// CORRECT - fix nested mapped type
type DeepMapped<T> = {
  [K in keyof T]: {
    [P in keyof T[K]]: T[K][P];  // ✓
  };
};

// Another example with conditional types:
// WRONG
type ConditionalMapped<T> = T extends object ? {
  [K]: T[K]  // Error: missing 'in'
} : never;

// CORRECT
type ConditionalMapped<T> = T extends object ? {
  [K in keyof T]: T[K]  // ✓
} : never;

// Check template literal types (TypeScript 4.1+):
// WRONG
type TemplateMapped = {
  [K in `prefix_${string}`]: K;  // ✓ This is actually correct syntax!
  // Template literal types work with 'in'
};

When debugging, break complex types into smaller parts to isolate the error.

6Use TypeScript playground to validate syntax

When unsure about mapped type syntax, use the TypeScript Playground to test:

1. Go to [TypeScript Playground](https://www.typescriptlang.org/play)
2. Paste your type definition
3. Check for errors in the editor
4. Compare with working examples:

typescript
// Working examples to compare:

// Basic mapped type
type Partial<T> = { [P in keyof T]?: T[P] };

// Mapped type with modifier
type Readonly<T> = { readonly [P in keyof T]: T[P] };

// Mapped type from union
type EventHandlers = { [E in 'click' | 'hover']: () => void };

// Mapped type with conditional value
type Nullable<T> = { [P in keyof T]: T[P] | null };

// Mapped type renaming keys (as clause)
type Getters<T> = {
  [P in keyof T as `get${Capitalize<string & P>}`]: () => T[P];
};

The playground provides instant feedback and helps you understand the correct syntax patterns.

Advanced notes

### Mapped Type Modifiers

TypeScript provides built-in modifiers for mapped types:

typescript
// Remove optionality ( -? )
type Concrete<T> = {
  [P in keyof T]-?: T[P];
};

// Remove readonly ( -readonly )
type Writable<T> = {
  -readonly [P in keyof T]: T[P];
};

// Add both readonly and optional
type ReadonlyPartial<T> = {
  readonly [P in keyof T]?: T[P];
};

### The "as" Clause (Key Remapping)

TypeScript 4.1+ introduced key remapping with the as clause:

typescript
// Rename keys
type Getters<T> = {
  [P in keyof T as `get${Capitalize<string & P>}`]: () => T[P];
};

// Filter keys
type MethodsOnly<T> = {
  [P in keyof T as T[P] extends Function ? P : never]: T[P];
};

// Transform key names with template literals
type ApiEndpoints = {
  [K in 'user' | 'product' as `/api/${K}`]: {
    get: () => Promise<any>;
    post: (data: any) => Promise<any>;
  };
};

### Mapped Types vs Conditional Types

Don't confuse mapped types with conditional types:

typescript
// CONDITIONAL TYPE (uses extends, not in)
type StringOrNumber<T> = T extends string ? string : number;

// MAPPED TYPE (uses in)
type OptionalProps<T> = {
  [K in keyof T]?: T[K];
};

// COMBINED: Mapped type with conditional value
type NullableProps<T> = {
  [K in keyof T]: T[K] | null;
};

### Common Built-in Mapped Types

TypeScript includes several useful mapped types:

typescript
// Partial<T> - all properties optional
type Partial<T> = { [P in keyof T]?: T[P] };

// Required<T> - all properties required
type Required<T> = { [P in keyof T]-?: T[P] };

// Readonly<T> - all properties readonly
type Readonly<T> = { readonly [P in keyof T]: T[P] };

// Pick<T, K> - subset of properties
type Pick<T, K extends keyof T> = { [P in K]: T[P] };

// Record<K, T> - object with specific keys
type Record<K extends keyof any, T> = { [P in K]: T };

### Performance Considerations

Complex mapped types can slow down TypeScript compilation:
- Very large unions (100+ members) in in position
- Deeply nested mapped types
- Recursive mapped types

Use interface instead of complex mapped types for frequently used types to improve performance.

Frequently asked questions

What does "Type parameter for mapped type must be 'in' expression" mean?
The "Type parameter for mapped type must be 'in' expression" error occurs when TypeScript encounters invalid syntax in a mapped type declaration. Mapped types are a powerful TypeScript feature that allows you to create new types by transforming properties of existing types. In TypeScript, mapped types use the syntax {[K in KeyType]: ValueType} where K is a type variable that iterates over each member of KeyType (typically a union type).
How do I fix "Type parameter for mapped type must be 'in' expression"?
This TypeScript error occurs when creating mapped types with incorrect syntax. Mapped types require the "in" keyword to iterate over union types, and this error appears when the type parameter is missing or malformed. The fix involves correcting the mapped type syntax to use proper "key in Type" pattern.
What causes "Type parameter for mapped type must be 'in' expression"?
Missing the "in" keyword in mapped type syntax: using {[K]: T} instead of {[K in Keys]: T} Typo in the "in" keyword (e.g., "inn", "on", or missing space) Using incorrect syntax for key iteration like {[K of Keys]: T}
Is the "Type parameter for mapped type must be 'in' expression" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading