提取 属性 个名称的安全方法
Safe way to extract property names
我正在寻找一种通过类型检查获取对象 属性 名称的方法,该方法允许在重构后捕获可能的回归。
这是一个示例:我必须将 属性 名称作为字符串传递的组件,如果我尝试更改模型中的 属性 名称,它将被破坏。
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>
);
}
}
如果有任何好的解决方案可以解决这个问题,我将不胜感激。
目前还没有真正好的方法,但目前有一些关于 github 的公开建议(参见 #1579, #394, and #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";
在 TS 2.1 中引入了 keyof
关键字,这使得这成为可能:
const propertyOf = <TObj>(name: keyof TObj) => name;
或
const propertiesOf = <TObj>(_obj: (TObj | undefined) = undefined) => <T extends keyof TObj>(name: T): T => name;
或使用Proxy
export const proxiedPropertiesOf = <TObj>(obj?: TObj) =>
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(myObj);
myInterfaceProperties.myProperty;
如果 myProperty
不是 MyObj
.
类型的 属性,这将给出错误
这是专门针对 React/React-Native 开发人员的。
为了安全地获得 属性-name,我使用下面的 class:
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')
获取 属性 名称。
您可以使用 keyof
和 Pick
:
将 属性 名称提取为字符串
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"'
我正在寻找一种通过类型检查获取对象 属性 名称的方法,该方法允许在重构后捕获可能的回归。
这是一个示例:我必须将 属性 名称作为字符串传递的组件,如果我尝试更改模型中的 属性 名称,它将被破坏。
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>
);
}
}
如果有任何好的解决方案可以解决这个问题,我将不胜感激。
目前还没有真正好的方法,但目前有一些关于 github 的公开建议(参见 #1579, #394, and #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";
在 TS 2.1 中引入了 keyof
关键字,这使得这成为可能:
const propertyOf = <TObj>(name: keyof TObj) => name;
或
const propertiesOf = <TObj>(_obj: (TObj | undefined) = undefined) => <T extends keyof TObj>(name: T): T => name;
或使用Proxy
export const proxiedPropertiesOf = <TObj>(obj?: TObj) =>
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(myObj);
myInterfaceProperties.myProperty;
如果 myProperty
不是 MyObj
.
这是专门针对 React/React-Native 开发人员的。
为了安全地获得 属性-name,我使用下面的 class:
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')
获取 属性 名称。
您可以使用 keyof
和 Pick
:
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"'