在Typescript中:是否有"编译时"方法来获取TypeScript接口中定义的所有属性名称?

use*_*621 24 generics interface typescript

我想创建一个通用的TypeScript类,用于渲染(作为HTML列表)实现特定TypeScript接口的对象数组.

例如

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'  
      ...

    }
}
Run Code Online (Sandbox Code Playgroud)

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

与C++模板一样,我相信TypeScript可以在"编译时"解析这些泛型,当TypeScript类型信息(如提供给用于实例化特定对象的泛型的接口)随时可用时.

由于可能提供了所有必需的类型信息,我只是好奇是否有可用于访问此信息的TypeScript扩展/工具,以及对'vanilla'Javascript对象的过度运行时过滤 - 由于模糊的继承问题,这可能会有问题(例如,如果运行时,泛型,Javascript(obj.hasOwnProperty(prop))用于过滤属性,则可能会过滤掉所需的TypeScript继承的接口属性).

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

如果存在标准(TypeScript)方法,我讨厌使用可能不完美的Javascript hack'重新发明轮子'.

真诚地:初学者TypeScript Guy,John

kim*_*ula 17

这可以通过https://github.com/Microsoft/TypeScript/pull/13940引入的自定义变换器实现,该变换器可在typescript @ next中获得.

我的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']
Run Code Online (Sandbox Code Playgroud)

  • 重要的是要知道“keys&lt;type&gt;();”应该在与定义的接口相同的文件中调用。花了几个小时..:) (5认同)
  • 这看起来不错,但似乎需要特殊的构建过程 - 对吗?如果还有一个 `optionalKeys` 函数,它也会很棒——它返回了可选项。这将使以类型安全的方式验证所需的道具运行时成为可能。 (2认同)

Fla*_*ken 6

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

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

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

  • _"除非你在编译期间存储它们"_:作为一个松散的实现,我在`MyClass`中创建了一个`静态PROP_NAMES:string [] = ['prop1','prop2','propN'];`.然后我做一个`MyClass.PROP_NAMES.forEach(key => {/*做某事*/}); (2认同)

Fen*_*ton 1

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

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();
Run Code Online (Sandbox Code Playgroud)

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

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