Is it possible to write a Mapped Type that transforms a Class into an Interface minus the class's methods or any properties assigned to the prototype
. EG,
class Dog {
name: string;
age: number;
bark() {}
get dogYears(): number {
return this.age * 7;
}
}
type InterfaceOf<T> = { /* ??? */ };
type IDog = InterfaceOf<Dog>;
// equivalent to
interface IDog {
name: string;
age: number;
}
Why do I want to do this? I'm looking to "deserialize" json objects into classes. Eg, I run a query to get dogs from the database, afterwards I'd like to instantiate them into class objects, perhaps by using the class-transformer library.
function queryDogs(): Promise<{ name: string, age: string }[]>;
function deserialize<T>(cls: (new() => T), input: InterfaceOf<T>): T;
function deserialize<T>(cls: (new() => T), inputs: InterfaceOf<T>[]): T[];
class Dog {
@Type(() => String)
name: string;
@Type(() => Number)
age: number;
bark() {}
get dogYears(): number {
return this.age * 7;
}
}
const dbDogs = await queryDogs();
const dogs: Dog[] = deserialize(Dog, dogs);
It would be nice if the deserialize
function knew if the input was the right shape to be deserialized into the Dog class. I was hoping it could look at the Dog
class that is given to it to transform it into the appropriate interface.
Interface Based on Class
You can directly generate an interface from a class in TypeScript:
The Angular community is all over this, but beware of some warnings about using classes as interfaces.
The interface that this would generate for you would include properties and methods:
Mapped Type Madness
Now, you can do something really clever/complex/mad with mapped types, based on the mapped types found in this article.
This takes the
DogLike
interface, and removesbark
anddogYears
.I included this as you mentioned mapped types. However, it is an insane solution.
Interface
My recommended solution, would be a a simple interface, and perhaps one that isn't named after dogs at all, as the properties are more general:
Okay, you may not name it exactly like that. However, simple is often best and when you come to change either the
Dog
class, or the interface that is loosely based on it at some point in the future, the simple interface will prove to be the best way to represent what you need.