在TypeScript中提取属性名称的安全方法

问题描述:

我正在寻找一种方法,通过类型检查来获取对象属性名称,以便在重构后捕获可能的回归。在TypeScript中提取属性名称的安全方法

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

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> 
    ); 
    } 
} 

我很感激,如果有什么好的解决方案来解决这个问题。

+1

目前在GitHub上的一些建议与此帮助(参见[#1579](https://github.com/Microsoft/TypeScript/issues/1579),[#394](HTTPS: //github.com/Microsoft/TypeScript/issues/394)和[#1003](https://github.com/Microsoft/TypeScript/issues/1003))。您可以查看[this](http://stackoverflow.com/a/32542368/188246),但要注意,代码缩小后可能无法使用。 –

+0

@DavidSherret你的'这个'解决方案是我能想出的唯一答案。请作为回答 – basarat

+0

@basarat会做,谢谢!对于a => a, –

在TS 2.1 keyof关键字引入这使得这一切成为可能:

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

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

这些可以是使用这样的:

propertyOf<MyObj>("myProperty"); 

const myObjProperties = propertyNamesOf<MyObj>(); 
myObjProperties("myProperty"); 

如果myProperty的是不是类型MyObj中的属性这将给出一个错误。

+0

这很好。这里是如何将它添加到类中的示例 https://gist.github.com/anonymous/5d5d041b4671480855070af478eb3fc2 –

现在还没有真正做到这一点的好方法,但目前在github上有一些开放的建议(请参阅#1579,#394#1003)。

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

这里有一个函数来做到这一点:

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"; 
+0

。属性我发现我需要从正则表达式中删除'\}' –