Safe way to extract property names

后端 未结 3 778
暗喜
暗喜 2020-12-14 01:34

I\'m looking for a way to get an object property name with typechecking that allows to catch possible regressions after refactoring.

Here\'s an example: the compone

相关标签:
3条回答
  • 2020-12-14 01:55

    In TS 2.1 the keyof keyword was introduced which made this possible:

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

    or

    const propertiesOf = <TObj>(_obj: (TObj | undefined) = undefined) => <T extends keyof TObj>(name: T): T => name;
    

    or using Proxy

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

    These can then be used like this:

    propertyOf<MyInterface>("myProperty");
    

    or

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

    or

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

    or

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

    This will give an error if myProperty is not a property of the type MyObj.

    0 讨论(0)
  • 2020-12-14 02:07

    Right now there's not really a great way of doing this, but there are currently some open suggestions on github (See #1579, #394, and #1003).

    What you can do, is what's shown in this answer—wrap referencing the property in a function, convert the function to a string, then extract the property name out of the string.

    Here's a function to do that:

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

    Then use it like so:

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

    This might not work depending on how the code is minified so just watch out for that.

    Update

    It's safer to do this at compile time. I wrote ts-nameof so this is possible:

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

    Compiles to:

    "name";
    
    0 讨论(0)
  • 2020-12-14 02:10

    This is specifically for React/React-Native developers.

    To safely get property-name, I use the below class:

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

    And replaced extends React.Component<PropTypes> with extends BaseComponnent<PropTypes,

    Now, with in the Component you can call, this.getPropName('yourPropName') to get the property name.

    0 讨论(0)
提交回复
热议问题