typescript remove optional property

7.9k views Asked by At

I'm trying to build a dynamic type for a builder

export type Builder<T, K extends keyof T> = {
    [P in K]: (value: T[P]) => Builder<T, K>;
} & {
    build(): Readonly<T>;
};

If I have a class or an interface with optional properties, I get this kind of error:

$ tsc
test/OtherClass.ts:29:1 - error TS2722: Cannot invoke an object which is possibly 'undefined'.

29 OtherClass.builder().patate(Patate.AU_FOUR).build();
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~

This is my class

export class OtherClass {
    constructor(
        public literal: string | undefined,
        public patate?: Patate,
        public hello: Readonly<Hello> = {},
    ) { }

    static builder: () => Builder<OtherClass, keyof OtherClass> = builder.for(OtherClass);
}

I was expecting the type to create a builder with a non-optional method for each properties, but for some reason, the optionality of patate seem inherent to the key and not the type. I don't get this behavior with the property literal

It looks like an issue to me. I'm using typescript 3.1.4. Is there another way to remove the question mark dynamically?

I've tried to use the NonNullable helper to create first a copy of my type with nothing nullable, but patate remains optional.

This is the effective type that vscode gives me

(property) patate?: ((value: Patate | undefined) => Builder<OtherClass, "literal" | "patate" | "hello">) | undefined
1

There are 1 answers

2
Nurbol Alpysbayev On BEST ANSWER

Does this help?

export type Builder<T, K extends keyof T> = {
    [P in K]-?: (value: T[P]) => Builder<T, K>;
} & {
    build(): Readonly<T>;
};

Note the -? which does what you want - removes optionality.