Javascript 自动将接口拆分为基本接口和附加接口
假设这些接口定义如下Javascript 自动将接口拆分为基本接口和附加接口,javascript,typescript,Javascript,Typescript,假设这些接口定义如下 interface ButtonProps { text: string; } interface DescriptiveButtonProps extends ButtonProps { visible: boolean, description: string; } 而且,我正在尝试渲染一个DescriptiveButton,它使用界面中定义的额外属性渲染一个按钮组件 class DescriptiveButton extends React
interface ButtonProps {
text: string;
}
interface DescriptiveButtonProps extends ButtonProps {
visible: boolean,
description: string;
}
而且,我正在尝试渲染一个DescriptiveButton
,它使用界面中定义的额外属性渲染一个按钮
组件
class DescriptiveButton extends React.Component<DescriptiveButtonProps, {}> {
render () {
const { visible, description, ...rest } = this.props;
return visible ? <div>{description}: <Button {...rest}/></div> : <div />;
}
}
class DescriptiveButton扩展了React.Component{
渲染(){
const{visible,description,…rest}=this.props;
返回可见?{description}::;
}
}
如你所见,我不得不手动列出所有额外的道具<代码>可见和
说明
。我想把DescriptiveButtonProps
分为ButtonProps
和其他部分,而不必全部列出。有没有办法做到这一点?如果要将一个对象拆分为两个对象,需要指定要在第一个输出对象中看到的关键点。类似这样的方法会奏效:
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];
}
这并不比您已经在做的更好,因为您正在数组中再次键入“可见”
和“说明”
。但是数组比变量中的变量名更容易操作,所以我们正朝着减少冗余的方向前进
从这里开始,我们的想法是创建一个运行时对象,其键是
“可见”
和“描述”
,而无需键入两次。问题是,您无法从接口派生值;类型系统处于运行时。您可以做相反的事情:从值派生接口。在您的案例中,有一种方法:
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> { };
最后,我们可以重写您的render()
方法:
const [xp , rest] = split(this.props, ["visible", "description"]);
// xp.visible, xp.description, and rest.text
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 />;
}
}
class DescriptiveButton扩展了React.Component{
渲染(){
常量[xp,rest]:[DescriptiveButtonExtraProps,ButtonOps]=
拆分(dp、descriptiveButtonExtraKeys);
返回xp.visible?{xp.description}::;
}
}
好了,结束了
所有这些都应该尽可能地工作,但这是一堆额外的机器,你需要随身携带,以节省重复的键名。只有当你有很多键名或者一个经常变化的键名列表时,这才可能是值得的;您不必一直确保解构赋值中的变量名与
DescriptiveButtonProps
的定义匹配。但是,如果您有一些属性或者它们不经常更改,那么最好保持代码的原有状态,并且要小心。这取决于你
希望有帮助。祝你好运
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 />;
}
}