@ahejlsberg Probably #29740 made this regression.
TypeScript Version: 3.4.0-dev.20190207
Search Terms:
Code
type DeepReadonly<T> =
T extends void ? T :
{ readonly [P in keyof T]: DeepReadonly<T[P]>; };
type m = { a: unknown }; // Also unknown[].
type i = DeepReadonly<m>;
Expected behavior:
i is { readonly a: unknown; }.
Actual behavior:
i is { readonly a: {}; }.
Playground Link:
Related Issues:
@falsandtru Doesn't seem to have to do with it being recursive, unknown is mapped to {} in simple mapped types and in 3.3 as well so its probably not related to #29740
type Mapped<T> = { [P in keyof T]: T[P] }
type m_unknown = Mapped<unknown> // {}
type m_any = Mapped<any> // { [x: string]: any; }
type m_never = Mapped<never> // never
This is definitely not a regression, mapped types have behaved this way since the introduction of the unknown type. That said, it might be more consistent to map unknown to unknown as it would better preserve the top-type aspect of unknown.
@ahejlsberg I judged that this is a regression since the following code make an error since 3.4.0-dev.20190207:
https://github.com/falsandtru/spica/blob/v0.0.222/src/type.test.ts#L368
The essential issue is mapped types replace unknown type with {} type as follows:
type Mapped<T> =
{ [P in keyof T]: T[P]; };
type a = Mapped<unknown>;
Conditional types are not related.
The difference of the behavior since that day is the return type of DeepReadonly<unknown[]> is changed from any[] to {}[]. Conditional types are needed for this behavior but not essential.
Most helpful comment
The essential issue is mapped types replace
unknowntype with{}type as follows:Conditional types are not related.
The difference of the behavior since that day is the return type of
DeepReadonly<unknown[]>is changed fromany[]to{}[]. Conditional types are needed for this behavior but not essential.