In angular 6, I have a typescript class like this
export class Hello {
id: number;
name?:string;
txt?:string;
}
From a component controller, I would like to retrieve an array with the property names, without needing to create an object. Something like:
ObjectType.keys(Hello);
// ["id", "name", "txt"]
Is that possible ?
i believe this is not possible but what is possible if you declare the property static and then access with direct reference of class like
class Hello{
static id: number;
static name?:string;
static txt?:string;
}
Hello.id;
obviously the other way is creating object by putting constructor in it and initialization with default value,
If the fields are not initialized even creating an object will not retrieve all members of the class. If a field is just declared, the compiler will know about it and offer type checking but it will not emit any code for it, so if you use Object.keys
only field that were assigned a value will be retrieved.
One option is to just create an object with all the same fields as the original (minus methods) and get the keys if this object. We can get the compiler to check that this object will have exactly the same fields as the class, no more and no less, so if we change the class we will get an error if we forget to change this object as well.
export class Hello {
id: number;
name?: string;
txt?: string;
method() { }
}
type NonMethodKeys<T> = { [P in keyof T]: T[P] extends Function ? never : P }[keyof T];
function getFields<T>(fields: { [P in NonMethodKeys<T>]: true }) {
return Object.keys(fields)
}
getFields<Hello>({
id: true,
name: true,
txt: true // if we comment this out we would get an error
//noAProp : true; //this would be an error
});
We can even extend this approach to creating an object that also has type information about the properties, again forcing the compiler to check that the object is accurate. For primitive types, we will pass a string representing the type name, for object properties we can either pass in the class constructor or just object
:
interface IProp { }
export class Hello {
id: number;
name?: string;
txt?: string;
subHi: Hello;
prop: IProp;
method() { }
}
type NonMethodKeys<T> = { [P in keyof T]: T[P] extends Function ? never : P }[keyof T];
type TypeOf<T> = T extends boolean ? 'boolean' :
T extends string ? 'string' :
T extends number ? 'number' :
'object' | (new (...args: any[]) => T);
function getFields<T>(fields: { [P in NonMethodKeys<T>]: TypeOf<T[P]> }) : typeof fields{
return fields
}
let fields = getFields<Hello>({
id: 'number',
name: 'string',
txt: 'string',
subHi: Hello,
prop: 'object'
});
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