Home > Net >  Make properties optional in typescript subclass
Make properties optional in typescript subclass

Time:11-20

I'm a little new to Typescript, I'm using Typescript 4.4 and I know of Utility types (Pick, Omit, Partial, ...). These however only work on types and interfaces and not on classes. I cannot use interfaces as I'm using TypeGraphQL and that framework expects classes instead of interfaces.

To minimize code duplication, I'm trying to do the following:

class User {
    id!: string;
    firstName!: string;
    lastName!: string;
    email!: string;
    street?:string;
    ... many more fields
}
class UserForUpdate extends Partial<User> {} //fails with 'Partial' only refers to a type, but is being used as a value here

or

class UserForUpdate extends User {
    id?: string; //fails with Type 'string | undefined' is not assignable to type 'string'.
    firstName?: string; //fails with Type 'string | undefined' is not assignable to type 'string'.
    lastName?: string; //fails with Type 'string | undefined' is not assignable to type 'string'.
    email?: string; //fails with Type 'string | undefined' is not assignable to type 'string'.
}

I also tried the following:

function forUpdating<T extends { new (...args: any[]) : any, prototype: any }>(ctor: T): Partial<T> & { new (...args: any[]): T } {
    return ctor as any;
}

export class TestUser extends forUpdating(User) {
    // fails with The types of 'prototype.id' are incompatible between these types.
    //   Type 'string | undefined' is not assignable to type 'string'.
    //      Type 'undefined' is not assignable to type 'string'.
    id?: string;
    firstName?: string;
    lastName?: string;
    email?: string;
}

Is there an easy way to make all required properties of a class optional?

CodePudding user response:

If your class only contains fields I would generally not recomend actually creating a class, you are much better off using an interface

class User {
    id!: string;
    firstName!: string;
    lastName!: string;
    email!: string;
    street?:string;
}
interface UserForUpdate extends Partial<User> {}

const user: UserForUpdate = {
    id: "",
}

Playground Link

If you want to bring in the fields from the interface to class you can use interface - class merging:

class User {
    id!: string;
    firstName!: string;
    lastName!: string; 
    email!: string;
    street?:string;
}
interface UserForUpdate extends Partial<User> {}
class UserForUpdate {

}

const user: UserForUpdate =  new UserForUpdate()
user.email = ""

Playground Link

  • Related