我在基于Typescript的应用程序中有一个相当复杂的React组件。仅当存在/存在另一个道具时才需要多组道具。有没有办法在Typescript中完成此操作?我还没有进行太多高级输入。
我尝试过使用有区别的工会,但是我认为这并不能完全涵盖所有可能性,因为可能会需要这些附加道具组的任意组合或完全不需要。
这就是我在这里使用的。
interface CommonProps {
...a bunch of props...
}
interface ManagedProps extends CommonProps {
managed: true;
...props for only when managed is present/true...
}
interface ServerSideProps extends CommonProps {
serverSide: true;
...props for only when serverSide is present/true...
}
interface Props = ???
基线是CommonProps
将适用于此组件。如果managed
为true
,则ManagedProps
也应适用。如果serverSide
为true
,则ServerSideProps
也适用。
我还没有这种情况,但是如果可选的道具组可以覆盖CommonProps
中定义的道具,那就太好了。
答案 0 :(得分:2)
使用ts-toolbelt的Union.Strict
帮助器取得了巨大的成功。
首先,让我们定义两个单独的可能类型集,将它们严格结合在一起,并编写一个type guard,告诉我们的React组件我们正在使用哪些道具。我将扩展您在OP中使用的示例:
import { Union } from 'ts-toolbelt';
interface CommonProps {
commonProp: string
}
interface ManagedProps extends CommonProps {
managed: true;
managedBoolean: boolean;
managedNumber: number;
}
interface ServerSideProps extends CommonProps {
serverSide: true;
serverBoolean: boolean;
serverNumber: number;
}
const isManaged = (props: Props): props is ManagedProps => {
return props.managed;
}
type Props = Union.Strict<ManagedProps | ServerSideProps>
现在,让我们编写一个利用我们编写的type guard的React组件:
const OurComponent: React.FC<Props> = (props) => {
if (isManaged(props)) {
return <div>Managed {props.commonProp}</div>
} else {
return <div>ServerSide {props.commonProp}</div>
}
}
如果使用错误的类型,这将导致错误。您可以在我创建的this StackBlitz中进行检查。
答案 1 :(得分:1)
您可以使用conditional types来获得类似的信息。例如:
interface CommonProps {
foo: string;
}
interface ManagedProps extends CommonProps {
managed: true;
managedOnlyProp: boolean;
}
interface ServerSideProps extends CommonProps {
serverSide: true;
serverOnlyProp: boolean;
}
type MappedProps<T> =
T extends { managed: true } ? ManagedProps :
T extends { serverSide: true } ? ServerSideProps :
CommonProps;
// Example function to test this:
declare function takeProps<T>(props: T & MappedProps<T>): void;
// And:
// This is OK, neither flag is present, so CommonProps are used:
takeProps({ foo: "" })
// This is an error. The managed flag is present, so we must also include the managed only props:
takeProps({ foo: "", managed: true }) // Gives error: Property 'managedOnlyProp' is missing in type '{ foo: string; managed: true; }' but required in type 'ManagedProps'.
// But this is okay, the flag is present but set to false...
takeProps({ foo: "", managed: false })
// And likewise for the serverSide versions:
takeProps({ foo: "", serverSide: true }) // Gives error: Property 'serverOnlyProp' is missing in type '{ foo: string; serverSide: true; }' but required in type 'ServerSideProps'.
takeProps({ foo: "", serverSide: true, serverOnlyProp: false }) // OK, no errors
takeProps({ foo: "", serverSide: false }) // OK, no errors
这里是Playground Link。
请注意,这仅适用于每个标志。结合使用时,您仍然可以传递无效的对象:
// This is wrong (missing serverOnlyProp) but no error is produced... :(
takeProps({foo: "", serverSide: true, managed: true, managedOnlyProp: false})