我有一堆"架构定义的抽象基类"类:
xyz
延伸BaseSchema
我想要确保的是父模式类正在为模式的属性(最终为它的关系)导出有意义的约束/接口。所以现在基类定义为:
export abstract class BaseSchema {
/** The primary-key for the record */
@property public id?: string;
/** The last time that a given model was updated */
@property public lastUpdated?: datetime;
/** The datetime at which this record was first created */
@property public createdAt?: datetime;
/** Metadata properties of the given schema */
public META?: Partial<ISchemaOptions>;
public toString() {
const obj: IDictionary = {};
this.META.properties.map(p => {
obj[p.property] = (this as any)[p.property];
});
return JSON.stringify(obj);
}
public toJSON() {
return this.toString();
}
}
示例父类可能如下所示:
export class Person extends BaseSchema {
// prettier-ignore
@property @length(20) public name: string;
@property public age?: number;
@property public gender?: "male" | "female" | "other";
// prettier-ignore
@property @pushKey public tags?: IDictionary<string>;
// prettier-ignore
@ownedBy(Person) @inverse("children") public motherId?: fk;
// prettier-ignore
@ownedBy(Person) @inverse("children") public fatherId?: fk;
@hasMany(Person) public children?: fk[];
@ownedBy(Company) public employerId?: fk;
}
现在您已经注意到我正在使用Typescript对装饰器的支持,在这种情况下,了解装饰器代码的主要内容是@property
decorator用于在架构上显式声明属性。这会将有关模式属性的元信息标记到模式类META.proproperties
上的字典对象中。您将在toString()
方法中稍后使用此功能。如果您觉得实际的装饰器代码很重要,您可以找到它HERE。
我想要能够做的是公开一个接口定义,该类型将类型约束为模式中定义的属性和类型。如下所示:
function foobar(person PersonProperties) { ... }
以便该物业&#34; person&#34;将受到所需属性的约束,并且编辑器中的 intellisense 将提供必需的(又名,&#34;名称&#34;)和不需要的属性(又名,&#34; age& #34;,&#34; createdAt&#34;等)定义为属性。
最终,我想导出一种对关系做同样事情的类型,但我现在很高兴能够获得架构的属性。
答案 0 :(得分:2)
在typescript 2.8中,您可以使用conditional types和mapped types来创建仅包含类的字段而不包含方法的类型,并保留字段的必需/可选属性:
type NonMethodKeys<T> = {[P in keyof T]: T[P] extends Function ? never : P }[keyof T];
type RemoveMethods<T> = Pick<T, NonMethodKeys<T>>;
class Person {
public name: string;
public age?: number;
public gender?: "male" | "female" | "other";
toJson(): string { return ''}
}
let ok: RemoveMethods<Person> = {
name : 'Snow',
gender: 'male'
};
// Error no name
let nokNoName: RemoveMethods<Person> = {
};
let nok: RemoveMethods<Person> = {
name : 'Snow',
gender: 'male',
toJson(): string { return ''} // error unknown property
};
如果您使用的是Typescript 2.7或更低版本,则没有条件类型,您只能使用Pick
或Partial
等映射类型。有关它们相对优势的讨论,您可以看到question
不幸的是,没有办法使用装饰器来辨别哪些字段进入界面,我们只能使用该字段的类型。您可能会考虑一种设计,其中您的类只包含属性的字段,或者此类字段保存在仅包含属性的特殊类中。
总是可以选择只显示属性的额外接口,但这会增加额外的维护麻烦。