感兴趣的挑战:是否可以根据给定的原型制作课程?

时间:2018-08-21 04:47:46

标签: mongodb typescript

说:已经有一个给定的架构定义对象:

const schema = {prop1:{type:String,maxLength:8},prop2 ...};

是否有可能:在不为每个架构对象声明接口的情况下,创建一个相应的类,该类可以生成具有从架构中提取的prop1:String,prop2 ...的文档。

我希望我的应用中有类似的内容:

// schema definition:
const PersonSchema = { name: { type: String, maxLength: 8 } };

// class factory
const PersonClass = SchemaClassFactory(PersonSchema);

// instance with props defined in schema.
let person1 = new PersonClass();
person1.name = 'Jack'; 
let person2 = new PersonClass();
person2.name = 3; // should be wrong hinted by tslint.

我该如何实现?

1 个答案:

答案 0 :(得分:2)

您可以使用映射类型和条件类型为模式对象创建一个类,以从模式中提取对象的形状。

下面是一个可能的解决方案,我不确定我是否涵盖了用mongoose定义架构的所有方法,但这应该会让您注目:

const PersonSchema = { 
    name: { type: String, maxLength: 8 },
    age: { type: Number },
    title: String,
    id: ObjectID
};

type PrimitiveConstructor<T> = {
    new (...a: any[]): any; 
    (...a: any[]): T
}

type Constructor<T> = {
    new (...a: any[]): T; 
}
type ExtractType<T> = {
    [P in keyof T] : 
        T[P] extends PrimitiveConstructor<infer U>? U :
        T[P] extends { type: PrimitiveConstructor<infer U> } ? U:
        T[P] extends Constructor<infer U> ? U :
        T[P] extends { type: Constructor<infer U> } ? U:
        never
}
function createClass<T>(schema: T): new (data?: Partial<ExtractType<T>>) => ExtractType<T> {
    // The class will not have the fields explicitly defined since we don't know them but that is fine 
    return new class {
        // Optional constructor for assigning data to the fields, you can remove this if not needed
        constructor(data?: any){
            if(data) {
                Object.assign(this, data);
            }
        }
    } as any;
}


var PersonClass = createClass(PersonSchema);
type PersonClass = InstanceType<typeof PersonClass>

let p = new PersonClass();
p.name ="";
p.name = 2; // error
p.id = new ObjectID(10);
let p2 = new PersonClass({
    name: "",
});