typescript 'compile-time' 获取所有属性名称定义接口的方式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30207661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 03:00:11  来源:igfitidea点击:

'compile-time' way to get all property names defined interface

typescriptgenericsinterface

提问by user3413621

I'd like to create a generic TypeScript class for rendering (as a HTML list) of an array of objects which implement a specific interface.

我想创建一个通用的 TypeScript 类来呈现(作为 HTML 列表)实现特定interface.

e.g.

例如

class GenericListRenderer<T> {
  items: T[];

 constructor(listItems: T[], className?: string){
      this.items = listItems;
      ...
    }

    private getPropertyNames(): string[]{

    // What is the best way to access all property names defined in
    // TypeScript interface 'T' that was used in this generic?
    ...   
    }

    render(){
      var propNames: string[] = this.getPropertyNames();
      // render list with each item containing set of all 
      // key(prop name)/value pairs defined by interface 'T'  
      ...

    }
}

Q: what would be the best way to get a 'compile-time' list of all property names defined in the specified () TypeScript interface?

问:获得在指定的 () TypeScript 接口中定义的所有属性名称的“编译时”列表的最佳方法是什么?

Like C++ templates, I believe that TypeScript could resolves these generics during "compile time", when TypeScript type information (like an interface supplied to the generic used to instantiate a particular object) is readily available.

与 C++ 模板一样,我相信 TypeScript 可以在“编译时”解析这些泛型,此时 TypeScript 类型信息(如提供给用于实例化特定对象的泛型的接口)很容易获得。

Since all the required type information is potentially supplied, I was just curious if there was a TypeScript extension/facility available to access this info w/o excessive runtime filtering of 'vanilla' Javascript objects -- which might be problematic due to ambiguous inheritance issues (e.g. desired TypeScript inherited interface properties may get filtered out if runtime, generic, Javascript (obj.hasOwnProperty(prop)) is used for filtering properties).

由于可能提供了所有必需的类型信息,我很好奇是否有可用的 TypeScript 扩展/工具来访问此信息,而无需对“vanilla”Javascript 对象进行过多的运行时过滤——这可能由于不明确的继承问题而出现问题(例如,如果使用运行时、泛型、Javascript (obj.hasOwnProperty(prop)) 过滤属性,则所需的 TypeScript 继承的接口属性可能会被过滤掉)。

This useful property introspection potential could be unambiguously resolved with TypeScript's super-set of type meta-data during 'compile-time' vs trying to resolve this information in the translated Javascript, when all of this type information is discarded.

这种有用的属性内省潜力可以在“编译时”期间使用 TypeScript 的类型元数据超集明确解决,而不是在所有这些类型信息都被丢弃时尝试在翻译的 Javascript 中解析此信息。

I'd hate to 'reinvent-the wheel' with a potentially imperfect Javascript hack if a standard (TypeScript) approach exists.

如果存在标准(TypeScript)方法,我不想用可能不完美的 Javascript hack 来“重新发明轮子”。

回答by kimamula

This is possible by using custom transformers introduced by https://github.com/Microsoft/TypeScript/pull/13940, which is available in typescript >= 2.4.1.

这可以通过使用https://github.com/Microsoft/TypeScript/pull/13940引入的自定义转换器来实现,该转换器在 typescript >= 2.4.1 中可用。

My npm package, ts-transformer-keys, is a good example.

我的 npm 包ts-transformer-keys就是一个很好的例子。

import { keys } from 'ts-transformer-keys';

interface Props {
  id: string;
  name: string;
  age: number;
}
const keysOfProps = keys<Props>();

console.log(keysOfProps); // ['id', 'name', 'age']

回答by Flavien Volken

This is not possible to retrieve that information at runtime, and they will never be per default possible unless you store them during the compilation. The solution is therefore be in reflection using ReflectDecorators.

这是不可能在运行时检索该信息的,除非您在编译期间存储它们,否则它们将永远不可能默认。因此,解决方案是使用ReflectDecorators进行反射。

Hereis an excellent article covering the question of retrieving compilation time metadata at the runtime. In short: you add a decorator to the interface you would like to keep the description, this one will be converted to a JSON object which one will be stored into the code itself. During the runtime, you will be able to retrieve this JSON object having all the interface data. This is now experimental (11th Feb 2016) but in a good way.

是一篇出色的文章,涵盖了在运行时检索编译时间元数据的问题。简而言之:您向要保留描述的界面添加一个装饰器,此装饰器将转换为 JSON 对象,该对象将存储到代码本身中。在运行时,您将能够检索此具有所有接口数据的 JSON 对象。这现在是实验性的(2016 年 2 月 11 日),但效果很好。

Note: The reason why it will never by per default is basically a choice of design for TS not to overload the js code with metadata (unlike Dart).

注意:默认情况下它永远不会的原因基本上是 TS 的设计选择,不要使用元数据重载 js 代码(与 Dart 不同)。

回答by Sethrone

You can get all the information you need by calling

您可以通过致电获得您需要的所有信息

let test = Object.keys(instanceOfObject)

If you log this console.log(test), you get something like:

如果你记录这个console.log(test),你会得到类似的东西:

0: "user_id"
...
26: "address"
length: 27

you can access every information on this object, such as test.length etc.

您可以访问此对象的所有信息,例如 test.length 等。

From: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

来自:https: //developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

回答by Fenton

At runtime all of the type information is erased, so the best you can do is enumerate the properties of one of the objects. This will give you back all properties, even those that were not on the specified interface.

在运行时,所有类型信息都会被删除,因此您能做的最好的事情就是枚举其中一个对象的属性。这将为您返回所有属性,即使是那些不在指定接口上的属性。

class GenericListRenderer<T> {

    constructor(private items: T[], private className?: string){

    }

    private getPropertyNames(): string[] {
        var properties: string[] = [];

        if (this.items.length > 0) {
            for (var propertyName in this.items[0]) {
                console.log(propertyName);
                properties.push(propertyName);
            }
        }

        return properties;
    }

    render(){
      var propNames: string[] = this.getPropertyNames();
    }

}

class Example {
    constructor(public name: string) {

    }
}

var example = new Example('Steve');

var a = new GenericListRenderer<Example>([example]);

a.render();

There is also Object.keys(), which gives you back all of the properties, although it is only supported in IE9 and above.

还有Object.keys(),它可以为您提供所有属性,尽管它仅在 IE9 及更高版本中受支持。

If you can supply more of a use case for what you want to do with the properties, it may be possible to give you an alternate solution using attributes or some other mechanism.

如果您可以为要对属性执行的操作提供更多用例,则可以使用属性或其他一些机制为您提供替代解决方案。