Reputation: 348
Since my class has async init process. I have to define a property readonly public but modify it internally like
declare function asyncAppMap(target: string): Promise<Window>
class FrameInternal {
public readonly content: Window | null = null
constructor(target: string) {
asyncAppMap(target).then(app => {
// Not possible currently.
// this.content = app
})
}
}
I am looking for some reusable utility like:
class FrameInternal{}
// Then all members of Frame becomes readonly
export const Frame: ReadonlyClass<FrameInternal> = FrameInternal
Upvotes: 2
Views: 376
Reputation: 330481
Depending on your specific needs, you could use something like this:
type ReadonlyClass<T extends new (...args: any) => any> =
T extends new (...args: infer A) => infer R ?
new (...args: A) => { readonly [K in keyof R]: R[K] } : never;
The type ReadonlyClass
converts a constructor type to a new constructor type that produces the same instance type with all its properties marked as readonly
.
When you export a class constructor you probably also want to export a type with the same name, corresponding to the instance type. This happens automatically when you use the class Foo {}
notation (Foo
is introduced as both the name of the class constructor value, and as the name of the class instance type):
export const Frame: ReadonlyClass<typeof FrameInternal> = FrameInternal;
export type Frame = InstanceType<typeof Frame>;
Which, when you inspect it, looks like this:
/*
const Frame: new (target: string) => {
readonly content: Window | null;
}
type Frame = {
readonly content: Window | null;
}
*/
That should work at least in the example case you showed above:
const f = new Frame("z");
f.content = null; // error, can't assign to read only
function acceptFrame(f: Frame) {
f.content = null; // error here too
}
Okay, hope that helps; good luck!
Upvotes: 2