如何在通用类型和非通用类型的交集中隔离已知属性
How to isolate known properties in an intersection of a generic type and a non-generic type
我有一个 HOC,它接受一个 withPaper
道具,但没有将它传递给它将渲染的组件。
import React, { ComponentType, FC } from "react";
import { Paper } from "@material-ui/core";
interface WithOptionalPaperProps {
withPaper?: boolean;
}
export const withOptionalPaper = <Props extends object>() => (
Component: ComponentType<Props>
) => ({ withPaper, ...otherProps }: Props & WithOptionalPaperProps) => {
if (withPaper) {
return (
<Paper>
<Component {...otherProps as Props} />
</Paper>
);
}
return <Component {...otherProps as Props} />;
};
// Code below shows how the code above will be used.
interface NonPaperedComponentProps {
text: string;
className: string;
}
const NonPaperedComponent: FC<NonPaperedComponentProps> = props => {
return <h1 className={props.className}>{props.text}</h1>;
};
// Code will be used like an HOC.
// 'withPaper' prop can be optionally added to wrap the underlying component in 'Paper'
const OptionalPaperedComponent = withOptionalPaper<NonPaperedComponentProps>()(
NonPaperedComponent
);
// All props except 'withPaper' should be passed to 'NonPaperedComponent'
const renderedComponent = (
<OptionalPaperedComponent withPaper className="Hello" text="Hello There" />
);
我已经通过 otherProps as Props
类型转换删除了错误。没有它们,它会产生错误 'Props' could be instantiated with a different subtype of constraint 'object'
https://codesandbox.io/s/gallant-shamir-z2098?file=/src/App.tsx:399-400
我会假设,因为我已经从 Props & WithOptionalPaperProps
中解构和隔离了已知属性,所以类型看起来像这样:
{
withPaper, // type 'WithOptionalPaperProps["withPaper"]'
...otherProps // type 'Props'
}
我怎样才能使 withOptionalPaper
returns 组件具有 withPaper
道具而不将其传递给其子级但仍传递所有其他道具?
这是对解构剩余对象类型的限制。对于 long 类型,TS 甚至不允许解构泛型类型参数。在 3.2 版中,添加了使用具有泛型类型参数的剩余变量的能力 (PR),但剩余变量的类型为 Pick<T, Exclude<keyof T, "other" | "props">>
,或等效的 Omit<T, "other" | "props">
。如果 T
已完全解析(即不是泛型类型参数),则条件类型 Exclude
的使用对于此函数的使用者来说将正常工作,但在函数内部,打字稿无法真正推理包含 Exclude
的类型。这只是条件类型工作方式的限制。您从 T
中排除,但由于 T
未知,ts 将推迟对条件类型的评估。这意味着 T
将无法分配给 Pick<T, Exclude<keyof T, "other" | "props">>
我们可以像你一样使用类型断言,这是我过去推荐的。应该避免使用类型断言,但是当您(即开发人员)拥有比编译器更多的信息时,它们可以提供帮助。这是其中一个案例。
为了更好的解决方法,我们可以使用一个技巧。虽然 Omit<T, "props">
不可分配给 T
,但它可以分配给自己。所以我们可以将组件道具键入 Props | Omit<Props, "withPaper">
。由于 Props
和 Omit<Props, "withPaper">
本质上是相同的类型,这无关紧要,但它会让编译器将其余对象分配给组件道具。
export const withOptionalPaper = <Props extends object>(
Component: ComponentType<Props | Omit<Props & WithOptionalPaperProps, keyof WithOptionalPaperProps>>
) => ( {withPaper, ...otherProps }: Props & WithOptionalPaperProps) => {
if (withPaper) {
return (
<Paper>
<Component {...otherProps} />
</Paper>
);
}
return <Component {...otherProps } />;
};
我有一个 HOC,它接受一个 withPaper
道具,但没有将它传递给它将渲染的组件。
import React, { ComponentType, FC } from "react";
import { Paper } from "@material-ui/core";
interface WithOptionalPaperProps {
withPaper?: boolean;
}
export const withOptionalPaper = <Props extends object>() => (
Component: ComponentType<Props>
) => ({ withPaper, ...otherProps }: Props & WithOptionalPaperProps) => {
if (withPaper) {
return (
<Paper>
<Component {...otherProps as Props} />
</Paper>
);
}
return <Component {...otherProps as Props} />;
};
// Code below shows how the code above will be used.
interface NonPaperedComponentProps {
text: string;
className: string;
}
const NonPaperedComponent: FC<NonPaperedComponentProps> = props => {
return <h1 className={props.className}>{props.text}</h1>;
};
// Code will be used like an HOC.
// 'withPaper' prop can be optionally added to wrap the underlying component in 'Paper'
const OptionalPaperedComponent = withOptionalPaper<NonPaperedComponentProps>()(
NonPaperedComponent
);
// All props except 'withPaper' should be passed to 'NonPaperedComponent'
const renderedComponent = (
<OptionalPaperedComponent withPaper className="Hello" text="Hello There" />
);
我已经通过 otherProps as Props
类型转换删除了错误。没有它们,它会产生错误 'Props' could be instantiated with a different subtype of constraint 'object'
https://codesandbox.io/s/gallant-shamir-z2098?file=/src/App.tsx:399-400
我会假设,因为我已经从 Props & WithOptionalPaperProps
中解构和隔离了已知属性,所以类型看起来像这样:
{
withPaper, // type 'WithOptionalPaperProps["withPaper"]'
...otherProps // type 'Props'
}
我怎样才能使 withOptionalPaper
returns 组件具有 withPaper
道具而不将其传递给其子级但仍传递所有其他道具?
这是对解构剩余对象类型的限制。对于 long 类型,TS 甚至不允许解构泛型类型参数。在 3.2 版中,添加了使用具有泛型类型参数的剩余变量的能力 (PR),但剩余变量的类型为 Pick<T, Exclude<keyof T, "other" | "props">>
,或等效的 Omit<T, "other" | "props">
。如果 T
已完全解析(即不是泛型类型参数),则条件类型 Exclude
的使用对于此函数的使用者来说将正常工作,但在函数内部,打字稿无法真正推理包含 Exclude
的类型。这只是条件类型工作方式的限制。您从 T
中排除,但由于 T
未知,ts 将推迟对条件类型的评估。这意味着 T
将无法分配给 Pick<T, Exclude<keyof T, "other" | "props">>
我们可以像你一样使用类型断言,这是我过去推荐的。应该避免使用类型断言,但是当您(即开发人员)拥有比编译器更多的信息时,它们可以提供帮助。这是其中一个案例。
为了更好的解决方法,我们可以使用一个技巧。虽然 Omit<T, "props">
不可分配给 T
,但它可以分配给自己。所以我们可以将组件道具键入 Props | Omit<Props, "withPaper">
。由于 Props
和 Omit<Props, "withPaper">
本质上是相同的类型,这无关紧要,但它会让编译器将其余对象分配给组件道具。
export const withOptionalPaper = <Props extends object>(
Component: ComponentType<Props | Omit<Props & WithOptionalPaperProps, keyof WithOptionalPaperProps>>
) => ( {withPaper, ...otherProps }: Props & WithOptionalPaperProps) => {
if (withPaper) {
return (
<Paper>
<Component {...otherProps} />
</Paper>
);
}
return <Component {...otherProps } />;
};