有没有办法在TypeScript中获取类的属性名称:在示例中 我想描述一下' A类或任何类获取其属性数组(也许只有公共属性?),是否可能?或者我应该首先实例化对象?
class A {
private a1;
private a2;
/** Getters and Setters */
}
class Describer<E> {
toBeDescribed:E ;
describe(): Array<string> {
/**
* Do something with 'toBeDescribed'
*/
return ['a1', 'a2']; //<- Example
}
}
let describer = new Describer<A>();
let x= describer.describe();
/** x should be ['a1', 'a2'] */
答案 0 :(得分:27)
此TypeScript代码
class A {
private a1;
public a2;
}
编译为此JavaScript代码
class A {
}
这是因为JavaScript中的属性只有在具有某些值后才会开始提升。您必须为属性分配一些值。
class A {
private a1 = "";
public a2 = "";
}
它编译为
class A {
constructor() {
this.a1 = "";
this.a2 = "";
}
}
但是,您无法从纯粹的类中获取属性(您只能从原型中获取方法)。您必须创建一个实例。然后通过调用Object.getOwnPropertyNames()
来获取属性。
let a = new A();
let array = return Object.getOwnPropertyNames(a);
array[0] === "a1";
array[1] === "a2";
class Describer {
static describe(instance): Array<string> {
return Object.getOwnPropertyNames(instance);
}
}
let a = new A();
let x = Describer.describe(a);
答案 1 :(得分:12)
有些答案存在部分错误,其中的一些事实也存在部分错误。
回答你的问题:是的!你可以。
在打字稿中
class A {
private a1;
private a2;
}
在Javascript中生成以下code:
var A = /** @class */ (function () {
function A() {
}
return A;
}());
正如@Erik_Cupal所说,你可以这样做:
let a = new A();
let array = return Object.getOwnPropertyNames(a);
但这是不完整的。如果您的类有自定义构造函数会发生什么?你需要使用Typescript做一个技巧,因为它不会编译。您需要指定为:
let className:any = A;
let a = new className();// the members will have value undefined
一般解决方案是:
class A {
private a1;
private a2;
constructor(a1:number, a2:string){
this.a1 = a1;
this.a2 = a2;
}
}
class Describer{
describeClass( typeOfClass:any){
let a = new typeOfClass();
let array = Object.getOwnPropertyNames(a);
return array;//you can apply any filter here
}
}
为了更好地理解,将根据具体情况引用。
答案 2 :(得分:8)
只是为了好玩
class A {
private a1 = void 0;
private a2 = void 0;
}
class B extends A {
private a3 = void 0;
private a4 = void 0;
}
class C extends B {
private a5 = void 0;
private a6 = void 0;
}
class Describer {
private static FRegEx = new RegExp(/(?:this\.)(.+?(?= ))/g);
static describe(val: Function, parent = false): string[] {
var result = [];
if (parent) {
var proto = Object.getPrototypeOf(val.prototype);
if (proto) {
result = result.concat(this.describe(proto.constructor, parent));
}
}
result = result.concat(val.toString().match(this.FRegEx) || []);
return result;
}
}
console.log(Describer.describe(A)); // ["this.a1", "this.a2"]
console.log(Describer.describe(B)); // ["this.a3", "this.a4"]
console.log(Describer.describe(C, true)); // ["this.a1", ..., "this.a6"]
更新:如果您使用的是自定义构造函数,则此功能将中断。
答案 3 :(得分:7)
另一个解决方案,你可以像这样迭代对象键,你必须首先实例化对象:
class Signup(View):
""" this class is used for user signup """
def get(self, request):
""" this function used to get the sign up form """
form = UserCreationForm()
return render(request, 'booking/signup.html', {'form': form})
def post(self, request):
""" this function used for post the sign up data """
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect('login')
class AuthLogin(View):
""" Its for login """
def get(self, request):
""" this function used to get the login form """
form = AuthenticationForm()
return render(request, 'booking/login.html', {'form': form})
def post(self, request):
""" this function used for post the login data """
form = AuthenticationForm(None, request.POST or None)
if form.is_valid():
login(request, form.get_user())
return redirect('/')
def home(request):
""" This is for displaying the home page """
return render(request, 'booking/home.html', {})
答案 4 :(得分:2)
使用这些
export class TableColumns<T> {
constructor(private t: new () => T) {
var fields: string[] = Object.keys(new t())
console.log('fields', fields)
console.log('t', t)
}
}
用法
columns_logs = new TableColumns<LogItem>(LogItem);
输出
fields (12) ["id", "code", "source", "title", "deleted", "checked", "body", "json", "dt_insert", "dt_checked", "screenshot", "uid"]
js类
t class LogItem {
constructor() {
this.id = 0;
this.code = 0;
this.source = '';
this.title = '';
this.deleted = false;
this.checked = false;
…
答案 5 :(得分:1)
我目前正在为Typescript开发类似于Linq的库,并希望在Typescript / Javascript中实现C#的GetProperty。我与Typescript和泛型一起使用的越多,得到的画面越清晰,通常您必须具有带有初始化属性的实例化对象,才能在运行时获取有关类属性的任何有用信息。但是,无论如何仅从构造函数对象或对象数组中检索信息,并且对此灵活一点,将是很好的。
这是我现在最后要讨论的内容。
首先,我定义Array原型方法(为您的C#开发人员使用“扩展方法”)。
export { } //creating a module of below code
declare global {
interface Array<T> {
GetProperties<T>(TClass: Function, sortProps: boolean): string[];
} }
然后,在madreason的答案的启发下,GetProperties方法看起来像这样。
if (!Array.prototype.GetProperties) {
Array.prototype.GetProperties = function <T>(TClass: any = null, sortProps: boolean = false): string[] {
if (TClass === null || TClass === undefined) {
if (this === null || this === undefined || this.length === 0) {
return []; //not possible to find out more information - return empty array
}
}
// debugger
if (TClass !== null && TClass !== undefined) {
if (this !== null && this !== undefined) {
if (this.length > 0) {
let knownProps: string[] = Describer.describe(this[0]).Where(x => x !== null && x !== undefined);
if (sortProps && knownProps !== null && knownProps !== undefined) {
knownProps = knownProps.OrderBy(p => p);
}
return knownProps;
}
if (TClass !== null && TClass !== undefined) {
let knownProps: string[] = Describer.describe(TClass).Where(x => x !== null && x !== undefined);
if (sortProps && knownProps !== null && knownProps !== undefined) {
knownProps = knownProps.OrderBy(p => p);
}
return knownProps;
}
}
}
return []; //give up..
}
}
describer方法与madreason的答案大致相同。它既可以处理Function类,又可以处理对象。如果没有给出类Function(即C#开发人员的类'type'),它将使用Object.getOwnPropertyNames。
class Describer {
private static FRegEx = new RegExp(/(?:this\.)(.+?(?= ))/g);
static describe(val: any, parent = false): string[] {
let isFunction = Object.prototype.toString.call(val) == '[object Function]';
if (isFunction) {
let result = [];
if (parent) {
var proto = Object.getPrototypeOf(val.prototype);
if (proto) {
result = result.concat(this.describe(proto.constructor, parent));
}
}
result = result.concat(val.toString().match(this.FRegEx));
result = result.Where(r => r !== null && r !== undefined);
return result;
}
else {
if (typeof val == "object") {
let knownProps: string[] = Object.getOwnPropertyNames(val);
return knownProps;
}
}
return val !== null ? [val.tostring()] : [];
}
}
在这里,您会看到两个规范,可以用Jasmine进行测试。
class Hero {
name: string;
gender: string;
age: number;
constructor(name: string = "", gender: string = "", age: number = 0) {
this.name = name;
this.gender = gender;
this.age = age;
}
}
class HeroWithAbility extends Hero {
ability: string;
constructor(ability: string = "") {
super();
this.ability = ability;
}
}
describe('Array Extensions tests for TsExtensions Linq esque library', () => {
it('can retrieve props for a class items of an array', () => {
let heroes: Hero[] = [<Hero>{ name: "Han Solo", age: 44, gender: "M" }, <Hero>{ name: "Leia", age: 29, gender: "F" }, <Hero>{ name: "Luke", age: 24, gender: "M" }, <Hero>{ name: "Lando", age: 47, gender: "M" }];
let foundProps = heroes.GetProperties(Hero, false);
//debugger
let expectedArrayOfProps = ["name", "age", "gender"];
expect(foundProps).toEqual(expectedArrayOfProps);
expect(heroes.GetProperties(Hero, true)).toEqual(["age", "gender", "name"]);
});
it('can retrieve props for a class only knowing its function', () => {
let heroes: Hero[] = [];
let foundProps = heroes.GetProperties(Hero, false);
let expectedArrayOfProps = ["this.name", "this.gender", "this.age"];
expect(foundProps).toEqual(expectedArrayOfProps);
let foundPropsThroughClassFunction = heroes.GetProperties(Hero, true);
//debugger
expect(foundPropsThroughClassFunction.SequenceEqual(["this.age", "this.gender", "this.name"])).toBe(true);
});
正如madreason所提到的,您必须初始化道具以从类Function本身获取任何信息,否则当Typescript代码转换为Javascript代码时,该信息就会被剥夺。
Typescript 3.7非常适合泛型,但是来自C#和反射背景,Typescript和泛型的一些基本部分仍然感觉有些松懈和未完成。就像这里的代码一样,但至少我得到了我想要的信息-给定类或对象实例的属性名称列表。
SequenceEqual是该方法吗?
if (!Array.prototype.SequenceEqual) {
Array.prototype.SequenceEqual = function <T>(compareArray: T): boolean {
if (!Array.isArray(this) || !Array.isArray(compareArray) || this.length !== compareArray.length)
return false;
var arr1 = this.concat().sort();
var arr2 = compareArray.concat().sort();
for (var i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i])
return false;
}
return true;
}
}
答案 6 :(得分:1)
这里还有一个也符合作者要求的答案:'compile-time' way to get all property names defined interface
如果您使用插件ts-transformer-keys和类的接口,则可以获取该类的所有键。
但是,如果您使用的是Angular或React,那么在某些情况下,还需要进行其他配置(webpack和typescript)才能使其正常工作:https://github.com/kimamula/ts-transformer-keys/issues/4
答案 7 :(得分:0)
其他答案主要是获取对象的全名,要获取属性的值,可以使用yourObj[name]
,例如:
var propNames = Object.getOwnPropertyNames(yourObj);
propNames.forEach(
function(propName) {
console.log(
'name: ' + propName
+ ' value: ' + yourObj[propName]);
}
);