1

I want to override the readonly modifier on a class property. Unfortunately the properties are private and I can't use something like type Writeable<T> = { -readonly [P in keyof T]: T[P] }; - as keyof does not work on privates.

I did extensive search and it seems like there is no way to get the type of all class properties, including the private ones (I would love to be proven wrong).

I have tried to come up with a helper type, where I would specify the property being accessed manually.

  1. I'm looking for help to fix BypassReadonly type so it does not result in any errors.
  2. I'm looking for more elegant methods to do this, without specifying the property (if it's possible at all).

Playground

type Writable<T> = { -readonly [P in keyof T]: T[P] };

type BypassReadonly<T extends {}, P extends keyof T> = Writable<T> & { -readonly [p in P]: T[P] }

// ts-error: Type 'P' cannot be used to index type 'T'.
type BypassReadonly2<T extends {}, P extends string> = Writable<T> & { [p in P]: T[P] }

class Test {
    private readonly privateProp!: string;

    public readonly publicProp!: string;

    public test() {
        // Works
        (this as Writable<this>).publicProp = 'test';
        
        // Doesn't work, private properties are dropped in keyof
        // ts-error: Property 'privateProp' does not exist on type 'Writable<this>'.
        (this as Writable<this>).privateProp = 'test';

        // Works but is too verbose
        (this as Writable<Test> & { privateProp: Test['privateProp'] }).privateProp = 'test';

        // Almost works, but there's an error related to use of keyof
        // ts-error: Type '"privateProp"' does not satisfy the constraint 'keyof Test'.
        (this as BypassReadonly<Test, 'privateProp'>).privateProp = 'test';

        // Works without keyof, but the implementation gives an error
        (this as BypassReadonly2<Test, 'privateProp'>).privateProp = 'test';
    }
}

I don't consider @ts-ignore or as any cast to be a valid solution as other type checks are lost. (though @ts-ignore could be used as a last resort in BypassReadonly2 type)

Maciej Krawczyk
  • 14,825
  • 5
  • 55
  • 67
  • There is a workaround https://stackoverflow.com/questions/57066049/list-private-property-names-of-the-class (see comments). Or you can just use `unique symbol` for private property and make it public like I did here tsplay.dev/Na0Kow . AFAIK, it is impossible to `keyof` private methods – captain-yossarian from Ukraine Sep 23 '21 at 07:53
  • Interesting solutions, but I don't want to complicate the structure / add more boilerplate I figure if I don't find a better solution, I will create a type that will allow to specify multiple private keys manually (not just one) and use that type for a variable alias. I mainly need this for constructor-like assignments when constructor cannot be used. And if I can't get around the errors, I will use ts-ignore once in the type definition. – Maciej Krawczyk Sep 23 '21 at 08:13

0 Answers0