假设我的这些接口定义如下。
interface ButtonProps {
text: string;
}
interface DescriptiveButtonProps extends ButtonProps {
visible: boolean,
description: string;
}
而且,我正在尝试使用接口中定义的额外属性来渲染一个DescriptiveButton
组件的Button
。
class DescriptiveButton extends React.Component<DescriptiveButtonProps, {}> {
render () {
const { visible, description, ...rest } = this.props;
return visible ? <div>{description}: <Button {...rest}/></div> : <div />;
}
}
如您所见,我不得不手动列出所有其他道具。 visible
和description
。我想将DescriptiveButtonProps
分成ButtonProps
和其他内容,而不必全部列出。有没有办法做到这一点?
答案 0 :(得分:2)
如果要将一个对象分成两个对象,则需要指定要在第一个输出对象中看到的键。这样的事情会起作用:
function split<T, K extends keyof T>(
obj: T, keys: K[]
): [Pick<T, K>, Pick<T, Exclude<keyof T, K>>] {
const pick = {} as Pick<T, K>;
const unpick = {} as Pick<T, Exclude<keyof T, K>>;
const keySet = {} as Record<K, boolean>;
keys.forEach(k => keySet[k] = true);
(Object.keys(obj) as (keyof T)[]).forEach(k => {
if (k in keySet) {
const kk = k as K;
pick[kk] = obj[kk];
} else {
const kk = k as Exclude<keyof T, K>
unpick[kk] = obj[kk];
}
});
return [pick, unpick];
}
您可以在render()
方法中使用它:
const [xp , rest] = split(this.props, ["visible", "description"]);
// xp.visible, xp.description, and rest.text
这并不比您已经做的好,因为您要在数组中再次键入"visible"
和"description"
。但是数组比destructuring assignment中的变量名称更易于操作,因此我们正朝着减少这种冗余的方向发展。
从这里开始,我们的想法是提出一个运行时对象,其键为"visible"
和"description"
,而无需键入两次。问题是您不能从接口派生值。运行时类型系统为erased。您可以执行相反的操作:从值派生接口。这是针对您的情况的一种方法:
interface ButtonProps {
text: string;
}
const descriptiveButtonExtraProps = {
visible: true,
description: "string"
}
type DescriptiveButtonExtraProps = typeof descriptiveButtonExtraProps;
type PropertyIntersect<T, U> = { [K in keyof (T & U)]: (T & U)[K] };
interface DescriptiveButtonProps extends
PropertyIntersect<ButtonProps, DescriptiveButtonExtraProps> { };
这可能很难理解,但是最后,DescriptiveButtonProps
正是您以前拥有的,但是您是从值descriptiveButtonExtraProps
派生出来的。这就是我们将用于获取拆分键列表的值:
const descriptiveButtonExtraKeys = Object.keys(descriptiveButtonExtraProps) as
(keyof DescriptiveButtonExtraProps)[];
最后,我们可以重写您的render()
方法:
class DescriptiveButton extends React.Component<DescriptiveButtonProps, {}> {
render () {
const [xp, rest]: [DescriptiveButtonExtraProps, ButtonProps] =
split(dp, descriptiveButtonExtraKeys);
return xp.visible ? <div>{xp.description}: <Button {...rest}/></div> : <div />;
}
}
就这样了。
所有这些都应该发挥作用,但这是一堆额外的机制,您需要四处寻找来保存重复的键名。仅当您有很多键名或键名列表经常变化时,这才值得。您不必确保解构分配中的变量名称与DescriptiveButtonProps
的定义相匹配。但是,如果您有一些属性,或者它们不经常更改,那么最好以使代码保持所拥有的方式并保持谨慎的态度可能会更好。由你决定。
希望有帮助。祝你好运!