Description
Bug Report
I was working with a library which reported that a property had an additional value of undefined
, and the author of the plugin claimed that the error went by removing readonly
. After investigating I found the following, which I found confusing.
The framework we use (vue) has a function for marking objects as deeply readonly:
export declare function readonly<T extends object>(target: T): DeepReadonly<T>;
export declare type DeepReadonly<T> = T extends {} ? {
readonly [K in keyof T]: DeepReadonly<T[K]>;
} : Readonly<T>;
When wrapping an object with optional properties:
export declare class User {
a?: string;
b: string;
}
export const user = readonly(new User() )
... the exported types have an additional undefined
at the type definition, even though it wasn't allowed in the original type.
export declare class User {
a?: string;
b: string;
}
export declare const user: {
readonly a?: string | undefined;
readonly b: string;
};
🔎 Search Terms
extra undefined, nested readonly, deepreadonly
🕗 Version & Regression Information
- This is the behavior in every version I tried.
⏯ Playground Link
Playground link with relevant code
💻 Code
This was the smallest I could reduce the code to and still see the compiler doing the unexpected:
export declare function readonly<T extends object>(target: T): DeepReadonly<T>;
export declare type DeepReadonly<T> = T extends {} ? {
readonly [K in keyof T]: DeepReadonly<T[K]>;
} : Readonly<T>;
export declare class User {
a?: string;
b: string;
}
export declare type ReadOnlyUser = DeepReadonly<User>
export const user = readonly(new User() )
🙁 Actual behavior
The code above is transformed to the following types. The generated type for the variable user
is incompatible with the exported class User
, because it adds undefined
as type to the type of the optional parameter of the class.
export declare const user: {
readonly a?: string | undefined;
readonly b: string;
};
🙂 Expected behavior
The types of User
and user
should be identical, the latter should just have all props as readonly
, but there should be no other changes to the type.
export declare const user: {
readonly a?: string;
readonly b: string;
};