提取属性名称的安全方法



我正在寻找一种通过类型检查获得对象属性名称的方法,该方法允许捕捉重构后可能的回归。

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

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

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

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

function propertyOf<TObj>(name: keyof TObj) {
    return name;
}

function propertiesOf<TObj>(_obj: (TObj | undefined) = undefined) {
    return function result<T extends keyof TObj>(name: T) {
        return name;
    }
}

或使用代理

export function proxiedPropertiesOf<TObj>(obj?: TObj) {
    return new Proxy({}, {
        get: (_, prop) => prop,
        set: () => {
        throw Error('Set not supported');
        },
    }) as {
        [P in keyof TObj]?: P;
    };
}

这些可以这样使用:

propertyOf<MyInterface>("myProperty");

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

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

const myInterfaceProperties = proxiedPropertiesOf<MyInterface>();
myInterfaceProperties.myProperty;

const myInterfaceProperties = proxiedPropertiesOf(myObj);
myInterfaceProperties.myProperty;

目前还没有一个很好的方法来做到这一点,但目前有一些关于github的公开建议(请参阅#1579、#394和#1003)。

你能做的就是这个答案中显示的内容——在函数中引用属性,将函数转换为字符串,然后从字符串中提取属性名称。

这里有一个功能:

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

然后像这样使用:

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

这可能不起作用,这取决于代码的缩小方式,所以请注意。

更新

在编译时这样做更安全。我写了的名字,所以这是可能的:

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

编译为:

"name";

这是专门为React/Rect 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')来获取属性名称。

您可以使用keyofPick:将属性名称提取为字符串

interface Test {
  id: number,
  title: string,
}
type TitleName = keyof Pick<Test, "title">;
     //^? type TitleName = "title"
const okTitle: TitleName = "title";
const wrongTitle : TitleName = "wrong";
     // Error: Type '"wrong"' is not assignable to type '"title"'

游乐场

相关内容

  • 没有找到相关文章

最新更新