I would like to create a class that has all the properties of an interface, but does not actually declare those properties itself.The interface properties are appended during the build process and WILL exist at runtime.
I found this post that pointed me in the direction of using Partial<T>
...but that doesn't seem to work. The following code produces no compile errors.
interface Animal {
name: string;
}
interface HasConstructor {
constructor: any;
}
//Do this to supress this error: "Type 'Dog' has no properties in common with type 'Partial<Animal>"
type OptionalAnimal = Partial<Animal> & HasConstructor;
class Dog implements OptionalAnimal {
public constructor() {
}
public breed: string;
}
However, the name
property is not available on the instance of Dog.
var spot = new Dog();
spot.name = "Spot"; //ERROR: Property 'name' does not exist on type 'Dog'
I can get around this issue by creating another type and referencing it like this:
type AnimalDog = Dog & Animal;
var spot: Animal = new Dog() as any;
spot.name = "Spot";
However, I can't construct a new instance of AnimalDog
, and have to cast as any
to get the types to line up, so I'm left using both AnimalDog
and Dog
in my code depending on the scenario. This also produces compile errors inside of Dog when referencing Animal types.
Is there a way to tell typescript that the class implements the interface, without explicitly declaring every interface property?
The problem is that Partial<T>
will only allow you to implement the members will not require you to do so, and if you don't implement the member it will not be in the class.
You can create a function that returns a class and this class will implement the interface. The returned class will not actually have to declare any of the fields so they will all be undefined
but this should be fine since the fields have to be optional anyway.
interface Animal {
name: string;
}
type OptionalAnimal = Partial<Animal>;
function autoImplement<T>(): new () => T {
return class { } as any;
}
class Dog extends autoImplement<OptionalAnimal>() {
public constructor() {
super();
}
public breed: string;
}
var spot = new Dog();
spot.name = "Spot"; // ok now
You can also cast the Dog
class to specify that the returned instance has the members of Animal
but these new members will not be accessible from inside the class:
interface Animal {
name: string;
}
class _Dog {
public constructor() {
}
public breed: string;
}
const Dog = _Dog as { new(): _Dog & Partial<Animal> } & typeof _Dog
type Dog = InstanceType<typeof Dog>
var spot = new Dog();
spot.name = "Spot";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With