This TypeScript error occurs when using a generic type parameter with keyof without proper constraints. The compiler cannot verify that the type parameter represents valid object keys without an explicit extends constraint.
This error appears when TypeScript's type system cannot guarantee that a generic type parameter represents valid property keys. The "keyof any" type represents all possible property keys in TypeScript (string | number | symbol), but when you use an unconstrained generic type parameter in a context that expects it to be a key type, TypeScript requires proof that the parameter will actually be a valid key. The error typically occurs in generic functions or types where you're trying to use a type parameter as an object key or constrain it with keyof, but haven't explicitly told TypeScript that this parameter should be limited to key types. Without proper constraints, TypeScript cannot verify type safety at compile time. This is a design feature of TypeScript's type system to prevent runtime errors where you might try to use a value that isn't actually a valid object key (like an object or array) as a property accessor.
If you have a function that needs a parameter to be a key of another type, use the extends keyof constraint:
// ❌ Error: K is not assignable to keyof any
function getProperty<T, K>(obj: T, key: K): T[K] {
return obj[key];
}
// ✅ Fixed: K is constrained to be a key of T
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}This tells TypeScript that K must be one of the keys of T, ensuring type safety.
If your generic needs to represent any valid object key (string, number, or symbol), constrain it to PropertyKey:
// ❌ Error without constraint
type MyMappedType<K> = {
[P in K]: string;
};
// ✅ Fixed: K must be a valid property key
type MyMappedType<K extends PropertyKey> = {
[P in K]: string;
};
// Or equivalently using keyof any
type MyMappedType<K extends keyof any> = {
[P in K]: string;
};Note: keyof any is equivalent to string | number | symbol (the PropertyKey type).
If you only need string keys, use a more specific constraint:
// Only allow string keys
function getStringProperty<T, K extends Extract<keyof T, string>>(
obj: T,
key: K
): T[K] {
return obj[key];
}
// Or for general use
type StringKeyedObject<K extends string> = {
[P in K]: any;
};This is useful when working with APIs that only accept string keys or when you need to manipulate keys as strings.
When creating mapped types, ensure your type parameter is properly constrained:
// ❌ Error: T not assignable to keyof any
type Getters<T> = {
[K in T]: () => K;
};
// ✅ Fixed: T constrained to valid keys
type Getters<T extends PropertyKey> = {
[K in T]: () => K;
};
// ✅ Better: Use with keyof to create getters for an object type
type ObjectGetters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};If you're building type utilities, ensure all generic parameters have appropriate constraints:
// ❌ Error in Pick-like utility
type MyPick<T, K> = {
[P in K]: T[P];
};
// ✅ Fixed with proper constraint
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
// Usage
interface User {
id: number;
name: string;
email: string;
}
type UserPreview = MyPick<User, 'id' | 'name'>; // Works!Review function signatures that use generic parameters as keys:
// ❌ Common mistake in accessor functions
function setValue<T, K>(obj: T, key: K, value: any): void {
obj[key] = value; // Error: K not assignable to keyof any
}
// ✅ Fixed with constraint and proper typing
function setValue<T, K extends keyof T>(
obj: T,
key: K,
value: T[K]
): void {
obj[key] = value;
}
// ✅ Alternative: Use Record type
function setValue<K extends string>(
obj: Record<K, any>,
key: K,
value: any
): void {
obj[key] = value;
}Understanding keyof any vs PropertyKey
The type keyof any is equivalent to PropertyKey, which is defined as string | number | symbol. This represents all possible types that can be used as object property keys in JavaScript.
When to use different constraints:
- K extends keyof T: When K should be limited to actual keys of a specific type T
- K extends PropertyKey or K extends keyof any: When K can be any valid object key
- K extends string: When you only want string keys (useful for template literal types)
- K extends Extract<keyof T, string>: When you want only the string keys from T
Known TypeScript limitations:
There are some edge cases where TypeScript's type system has limitations with keyof constraints, particularly when combining Record<string, unknown> with keyof T. In these cases, TypeScript may report that keyof T is not assignable to string because it includes symbol and number keys. You can work around this using Extract<keyof T, string> or type assertions when you're certain about the key types.
Generic constraint chaining:
You can chain constraints for more complex scenarios:
function getNestedProperty<
T,
K1 extends keyof T,
K2 extends keyof T[K1]
>(obj: T, key1: K1, key2: K2): T[K1][K2] {
return obj[key1][key2];
}This ensures type safety through multiple levels of property access.
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript