Issue
Consider the following TypeScript classes:
class A {
foo: string;
constructor({ foo }: { foo: string }) {
this.foo = foo;
}
equals(other: A) {
return this.foo === other.foo;
}
}
class B extends A {
bar: number;
constructor(b: {
foo: string;
bar: number;
}) {
super({ foo: b.foo });
this.bar = b.bar;
}
}
const b = new B({
foo: 'Test',
bar: 42,
});
In reality, class B has about 20 properties which makes the class and especially the constructor definition super verbose because every property is repeated three separate times. How could I make it more compact?
You can't do constructor({ foo, bar }: B)
because B also requires the object to have things like equals()
.
I also tried the following but same result:
constructor(b: { [K in keyof B]: B[K] }) {
super({ foo: b.foo });
.
.
.
Argument of type '{ foo: string; bar: number; }' is missing the following properties from type '{ [K in keyof B]: B[K] }': equals.ts(2345)
Solution
There's a couple different approaches you can take.
Introspect the classes themselves
Given a couple helper types, you can do
type NonFunctionFieldNamesOfType<T> = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T];
type NonFunctionFields<Tc> = Pick<Tc, NonFunctionFieldNamesOfType<Tc>>;
class A {
foo: string;
constructor({ foo }: NonFunctionFields<A>) {
this.foo = foo;
}
equals(other: A) {
return this.foo === other.foo;
}
}
class B extends A {
bar: number;
constructor(b: NonFunctionFields<B>) {
super({ foo: b.foo });
this.bar = b.bar;
}
}
const b = new B({
foo: "Test",
bar: 42,
});
You can of course also limit those types using Pick
and Omit
if required.
Using ConstructorParameters
You can also use ConstructorParameters
to introspect the superclass's constructor's parameters, and destructuring in the subclass's constructor.
This could be useful for more complex cases.
With ConstructorParameters
, you could at least get to
foo: string;
constructor({ foo }: { foo: string }) {
this.foo = foo;
}
equals(other: A) {
return this.foo === other.foo;
}
}
class B extends A {
bar: number;
constructor({ bar, ...a }: ConstructorParameters<typeof A>[0] & { bar: number }) {
super(a);
this.bar = bar;
}
}
const b = new B({
foo: "Test",
bar: 42,
});
Answered By - AKX
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.