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 component where I have to pass the property names as strings and it will be broken if I'll try to change the property names in the model.
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>
);
}
}
I'd appreciate if there's any nice solution to solve this issue.
In TS 2.1 the keyof
keyword was introduced which made this possible:
function propertyOf<TObj>(name: keyof TObj) {
return name;
}
or
function propertiesOf<TObj>(_obj: (TObj | undefined) = undefined) {
return function result<T extends keyof TObj>(name: T) {
return name;
}
}
or using Proxy
export function proxiedPropertiesOf<TObj>(obj?: TObj) {
return 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<MyInterface>();
myInterfaceProperties.myProperty;
or
const myInterfaceProperties = proxiedPropertiesOf(myObj);
myInterfaceProperties.myProperty;