提取属性名称的安全方法

时间:2015-11-05 14:48:07

标签: typescript reflection metaprogramming

我正在寻找一种方法来获取带有类型检查的对象属性名称,以便在重构后捕获可能的回归。

这是一个例子:我必须将属性名称作为字符串传递的组件,如果我将尝试更改模型中的属性名称,它将被破坏。

interface User {
   name: string;
   email: string;
}

class View extends React.Component<any, User> {

   constructor() {
      super();
      this.state = { name: "name", email: "email" };
   }

   private onChange = (e: React.FormEvent) => {
      let target = e.target as HTMLInputElement;
      this.state[target.id] = target.value;
      this.setState(this.state);
   }

   public render() {
      return (
         <form>
            <input
               id={"name"}
               value={this.state.name}
               onChange={this.onChange}/>
            <input
               id={"email"}
               value={this.state.email}
               onChange={this.onChange}/>
            <input type="submit" value="Send" />
         </form>
      );
   }
}

如果有任何解决此问题的解决方案,我会很感激。

3 个答案:

答案 0 :(得分:25)

在TS 2.1中引入了keyof关键字,使其成为可能:

const propertyOf = <TObj>(name: keyof TObj) => name;

const propertyNamesOf = <TObj>(obj: TObj = null) => (name: keyof TObj) => name;

然后可以这样使用:

propertyOf<MyInterface>("myProperty");

const myInterfaceProperties = propertyNamesOf<MyInterface>();
myInterfaceProperties("myProperty");

const myInterfaceProperties = propertyNamesOf(myObj);
myInterfaceProperties("myProperty");

如果myProperty不是MyObj类型的属性,则会出错。

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html

答案 1 :(得分:22)

目前还没有一种很好的方法可以做到这一点,但目前github上有一些公开的建议(见#1579#394#1003)。

你可以做什么,是this answer中显示的内容 - 在函数中引用属性,将函数转换为字符串,然后从字符串中提取属性名称。

这是一个执行此操作的功能:

function getPropertyName(propertyFunction: Function) {
    return /\.([^\.;]+);?\s*\}$/.exec(propertyFunction.toString())[1];
}

然后像这样使用它:

// nameProperty will hold "name"
const nameProperty = getPropertyName(() => this.state.name);

这可能不起作用,具体取决于代码的缩小方式,因此请注意这一点。

<强>更新

在编译时这样做更安全。我写了ts-nameof所以这是可能的:

nameof<User>(s => s.name);

编译为:

"name";

答案 2 :(得分:2)

这是专门针对React / React-Native开发人员的。

为了安全地获取属性名称,我使用以下类:

export class BaseComponent<P = {}, S = {}> extends Component<P, S> {
  protected getPropName = (name: keyof P) => name;
  protected getStateName = (name: keyof S) => name;
}

然后将extends React.Component<PropTypes>替换为extends BaseComponnent<PropTypes

现在,在Component中,您可以调用this.getPropName('yourPropName')来获取属性名称。