我试图定义我的数据结构来封装在一个类中处理数据的逻辑。然后我有拥有此信息的Field类。
Field<T>(private name:string, private size:number, private comment:string) {
}
get Name():string {
return this.name;
}
get Size():number {
return this.size;
}
创建一个Field引用:
class User {
public FirstName:Field<string> = new Field<string>('FirstName', 20);
public LastName:Field<string> = new Field<string>('LastName', 32);
public Age:Field<number> = new Field<number>('Age', 3);
}
上面的意思是我有一个数据字段'FirstName',它是一个字符串,最多20个字符。 'LastName'是32个字符的字符串,Age可以是3个数字。
我使用它来验证表单上的数据(使用Size来限制可输入的字符数)以及从外部API读取时。
如果我从外部API获取数据,我还可以使用“大小”字段来限制我复制到字段中的数据量,以便截断数据。
这允许我的数据接口层使用数据类型类,期望所有字段都是Field<T>
,然后允许我使用我的库函数来控制数据大小,向表单添加数据验证等,而不必总是写验证HTML中的函数,因为我可以在Angular中使用循环并从数据结构中提取信息。
我现在的问题是如何获得一个通用接口来处理来自AngularFire中列表和对象的数据。
通常,当从AngularFire访问数据和结构时,我可以使用:
constructor(public afDb:AngularFireDatabase) {
...
this.afDb.object<IUser>('/user/1').valueChanges();
...
}
这将获取数据并自动将其解析为IUser接口(上面未显示)。
我希望能够从我的User类生成一个IUser接口,该接口具有Field<T>
中的数据结构。基本上我想从User类生成一个接口,如:
export interface IUser {
FirstName?:string;
LastName?:string;
Age?:number;
}
然后可以在我访问AngularFire时使用此接口。另一个选项/问题是如何做相当于afDb.object<IUser>...
并关闭<IUser>
,但能够将AngularFire对象的结果解析为我的数据结构,即User类。所以解析会调用Field<T>.SetValue();
或其他东西。
如果你想构建一个完全通用的接口来处理具有多个Field<T>
s的所有不同对象,那么你应该考虑创建这样的东西:
class Field<T> {
constructor(private name: string, private size: number) {
}
}
interface IField {
[index: string]: Field<string | number>;
}
interface IWhatever {
fields: ArrayLike<IField>;
}
这样你就可以使用IWhatever
和afDb.object<IWhatever>()
并获得一个IWhatever
,它有一个Array
类型的IField
,这是一个非常通用的接口,可以容纳任意数量的命名属性,每个属性都具有混凝土的值类型Field<string>
或Field<number>
(您可以根据需要扩展这些类型)。
这是你想要的?
- 更新更多有用的指导 -
在阅读您的评论并再次回顾您的答案之后,我认为我现在更了解您可能需要的内容。看看下一个例子,我认为它更适合你想做的事情。我评论了每个类和接口,以便更清楚地理解整个概念。如果您需要更多说明以及是否有帮助,请告诉我。
// This is a implementation class of our concept of "Field" objects.
// The T is a generic type, which means that it can be any type every time
// you instantiate a new object of this class.
// the type will be used to define the type of the `value` variable
// that will hold the actual internal value of the "Field".
//
// So when you create a new Field<string>(....) you will always know
// that the `value` property will be of type `string` and not anything else.
class Field<T> {
public title: string;
public maxLength: number;
public value: T;
constructor(title: string, maxLength: number) {
this.title = title;
this.maxLength = maxLength;
}
}
// this is an interface, that defines an object with any number
// of properties of type Field<string> or Field<number>
interface IObject {
// can have any number of Field typed properties
[index: string]: Field<string | number>;
}
// this is a more specific version of the above interface, that
// actually defines exactly which fields and their types it
// should have and which ones should be required or optional
interface IUser {
// required fields
firstName: Field<string>;
lastName: Field<string>;
age: Field<number>;
// lets define an optional one
favoriteColor?: Field<string>;
}
// Suppose that we get a data structure from somewhere that has no type
// and that we want to encapsulate it inside one of our interfaces
// in order to make it easier to work with it
//
// So lets create a literal object with no specific type (a data structure):
let data = {
firstName: new Field<string>('First Name', 20),
lastName: new Field<string>('Last Name', 32),
age: new Field<number>('Age', 3),
}
// we can then assign this object or data structure to a
// variable with the very generic IObject as type
let anObjectOfUnknownType: IObject = data;
// no problem, no complaints from typescript, the data is compatible
// with our IObject interface!
// We can also assign it to a variable
// of type IUser, which is more specific
// and narrows down our data structure to the definition that
// we the IUser interface expects it to be. For this to work
// though we must make sure that the structure must satisfy
// and be compatible with the IUser interface.
let userDataStructure: IUser = data;
// and yes, it works, because the data is compatible with IUser
// We now have encapsulated the "unknown" data structure in a
// useful typed variable from which we can access its properties
// and enjoy type checking and intellisense
console.log("user's full name is: " + userDataStructure.firstName.value + " " + userDataStructure.lastName.value);
console.log("user's age is: " + userDataStructure.age);
if (typeof userDataStructure.favoriteColor !== "undefined") {
console.log("user's favorite color is: " + userDataStructure.favoriteColor.value);
}