Reputation: 3068
I have a class Client
and I want to create a new class UpdateClient
but omitting few properties of class Client
.
class Client {
constructor() {
this.clients = '';
this.client_secret = '';
}
clients: string;
client_secret: string;
}
I want class UpdateClient
to be like this
class UpdateClient {
constructor() {
this.clients = '';
}
clients: string;
}
Now, I'm sure there will be few approaches in vanilla JS by which I can get the task done, like iterating over all enumerable properties of class client
, but I don't want to that.
I want a typescript specific solution. I found Omit
type utility and it's working as expected. However, there's a small issue which I'm unable to fix.
This is the whole code snippet
class Client {
constructor() {
this.clients = '';
this.client_secret = '';
}
clients: string;
client_secret: string;
}
type T = Omit<Client, 'client_secret'>
I'm getting a type instead of a class. I want to somehow convert this type T
to the class UpdateClient
and export it. The exported property needs to be a class because the other module using this one expects a class.
I'm using typescript v3.7.5
Upvotes: 2
Views: 6959
Reputation: 1229
This feels like your object hierarchy is upside down. Even though this is the order that you've developed this in, doesn't mean you cannot insert the simpler class as the superclass of the existing one.
class BaseClient {
constructor() {
this.clients = '';
}
clients: string;
}
class Client extends BaseClient {
constructor() {
this.client_secret = '';
}
client_secret: string;
}
Now you have the two classes you want and they're related in the way you want. You might want to rename the two (maybe Client
and ClientWithSecret
), but do that as a refactor so existing references to Client
update to point to the right one.
If you want to add anything shared, then add it to BaseClient
. If the two need to diverge, then create a new subclass (extends
) for that purpose.
Upvotes: 0
Reputation: 328618
If all you want is for UpdateClient
to be a class constructor that makes instances of Omit<Client, 'client_secret'>
, you can write it this way:
const UpdateClient: new () => Omit<Client, 'client_secret'> = Client;
The declared type new () => ...
means "a constructor which takes no arguments and produces an instance of ...". The syntax is either called a constructor signature or "new
able" and is part of the static side of a class.
The fact that the above code, assigning Client
to the variable UpdateClient
, compiles without error shows that the compiler agrees that Client
does act like a no-arg constructor of Omit<Client, 'client_secret'>
. If, for example, Client
's constructor required an argument, or if Omit<Client, 'client_secret'>
weren't a supertype of Client
, you'd get an error:
class RequiresArg {
constructor(public clients: string) { }
}
const Oops: new () => Omit<Client, 'client_secret'> = RequiresArg; // error
// Type 'typeof RequiresArg' is not assignable to type 'new () => Pick<Client, "clients">'
class NotCompatible {
clients?: number;
}
const StillOops: new () => Omit<Client, 'client_secret'> = NotCompatible; // error
// Type 'number | undefined' is not assignable to type 'string'.
Anyway, then this will work:
const c = new UpdateClient();
c.clients; // okay
c.client_secret; // error at compile time, although it does exist at runtime
Do note that even though UpdateClient
's instances are not known by the compiler to have a client_secret
property, it's still just an instance of Client
at runtime, so the property will definitely exist at runtime. If that's a problem you should probably do something completely different. But since you said Omit<...>
works for you, I guess that's not an issue.
Okay, hope that helps; good luck!
Upvotes: 5