Closed
Description
With the upcoming conditional types in 21316, it will become possible to write mapped types that handle primitive types correctly. However, there's currently no support from the compiler to warn that a mapped type is being incorrectly applied to a primitive (see example below). I suggest two changes:
- Add a compiler flag that only allows a type that extends object to be used in a mapped type. A potential solution would be to disallow applying
keyof
to a primitive type. - Rewrite commonly used mapped types such as
Partial
using conditional types, so that code applying them to primitives can compile using the new flag.
Example of how the current behavior of mapping primitive types to themselves (introduced in 12447) can go wrong:
type Lazy<T> = {
[K in keyof T]: () => T[K];
};
type LazyContainer<T> = {
val: Lazy<T>;
}
// This should definitely be an error, but it's not
const lazyContainer: LazyContainer<string> = { val: 'abc' };
function strictify<T>(x: Lazy<T>): T {
const result: Partial<T> = {};
for (const k in x) {
result[k] = x[k]();
}
return result as T;
}
function strictifyContainer<T>(x: LazyContainer<T>): T {
return strictify(x.val);
}
const strictString = strictifyContainer(lazyContainer); // runtime type error
With the new flag applied:
type Lazy<T> = {
[K in keyof T]: () => T[K]; // error, T is not a subtype of object
};