Yes, this solution was effective for me.
// ---- . ---- ---- ---- ---- . ----
// Custom Class Foo:
// ---- . ---- ---- ---- ---- . ----
type FooInit = {
readonly prop01?: string | undefined;
};
type FooInterface =
Required<FooInit>;
class Foo
implements
FooInterface
{
public readonly prop01: string;
public constructor(
init?: FooInit | undefined
) {
this.prop01 = init?.prop01 ?? "default prop01";
}
};
// ---- . ---- ---- ---- ---- . ----
// Custom Class Bar:
// ---- . ---- ---- ---- ---- . ----
type BarInit <
GenericFooInit extends FooInit
> = {
readonly foo?: GenericFooInit | undefined
}
type BarInterface <
GenericFoo extends Foo
> = {
readonly foo: GenericFoo
}
class Bar <
GenericFooInit extends FooInit,
GenericFoo extends Foo
>
implements
BarInterface<GenericFoo>
{
public readonly foo: GenericFoo;
public constructor(
GenericFooConstructor: new (
init?: GenericFooInit | undefined
) => GenericFoo,
init?: BarInit<GenericFooInit> | undefined
) {
this.foo = new GenericFooConstructor(init?.foo);
}
// Custom method 'make'
public static readonly make = <
GenericFooInit extends FooInit,
GenericFoo extends Foo
> (
GenericFooConstructor: new (
init?: GenericFooInit | undefined
) => GenericFoo,
init?: BarInit<GenericFooInit> | undefined
): Bar <
GenericFooInit,
GenericFoo
> =>
new Bar <
GenericFooInit,
GenericFoo
> (
GenericFooConstructor,
init
)
};
// ---- . ---- ---- ---- ---- . ----
// Example of Use:
// ---- . ---- ---- ---- ---- . ----
type NeoFooInit = FooInit & {
prop02?: string | undefined;
};
type NeoFooInterface =
Required<NeoFooInit>
class NeoFoo
extends
Foo
implements
NeoFooInterface
{
public readonly prop02: string;
public constructor(
init?: NeoFooInit | undefined
) {
super(init);
this.prop02 = init?.prop02 ?? "default prop02";
};
};
const bar01 = Bar.make <NeoFooInit, NeoFoo> (NeoFoo);
const bar02 = Bar.make <NeoFooInit, NeoFoo> (NeoFoo, {});
const bar03 = Bar.make <NeoFooInit, NeoFoo> (NeoFoo, {
foo: {}
});
const bar04 = Bar.make <NeoFooInit, NeoFoo> (NeoFoo, {
foo: {
prop01: "prop01"
}
});
const bar05 = Bar.make <NeoFooInit, NeoFoo> (NeoFoo, {
foo: {
prop02: "prop02"
}
});
const bar06 = Bar.make <NeoFooInit, NeoFoo> (NeoFoo, {
foo: {
prop01: "prop01",
prop02: "prop02"
}
});
const bar07 = Bar.make <NeoFooInit, NeoFoo> (NeoFoo, {
foo: {
prop01: "prop01",
prop02: "prop02",
prop03: "prop03" // Generates error message as follows:
// Type '{ prop01: string; prop02: string; prop03: string; }' is not assignable to type 'NeoFooInit'.
// Object literal may only specify known properties, but 'prop03' does not exist in type 'NeoFooInit'. Did you mean to write `'prop01'`? ts(2322)
}
});