Reputation: 69
I am developing in a React + TypeScript environment.
I want to has multiple keys to the 'content' key.
interface IModalProps {
isOpen: boolean;
type: 'basic';
content: ReactElement;
options?: IModalOption;
}
I imagined it with the code below.
interface IModalProps {
isOpen: boolean;
type: 'basic';
[content | children]: ReactElement;
options?: IModalOption;
}
the code above means key would be 'content' or 'children'.
Is there a way to have multiple keys in the type script? thanks.
Upvotes: 1
Views: 1324
Reputation: 4112
Does this do what you want?
interface IModalPropsBase {
isOpen: boolean;
type: 'basic';
options?: IModalOption;
}
type IModalProps = IModalPropsBase
& ({ content: ReactElement } | { children: ReactElement });
Or mashed into a signle type in case you prefer that:
type IModalProps =
& { isOpen: boolean; type: 'basic'; options?: IModalOption; }
& ({ content: ReactElement } | { children: ReactElement });
To then use it, you can utilize the in
operator:
function Modal(props: IModalProps) {
const actualContent = 'children' in props ? props.children : props.content;
// ...
}
Upvotes: 1
Reputation: 33041
import { ReactElement } from 'react'
type IModalOption = {
tag: 'IModalOption'
}
interface Props {
isOpen: boolean;
type: 'basic';
options?: IModalOption;
}
type Union<T extends string> = T extends string ? Record<T, ReactElement> : never
type IModalProps = Props & Union<'content' | 'children'>
// error, there are no 'content' and/or 'children'
const props: IModalProps = {
isOpen: true,
type: 'basic',
options: {
tag: 'IModalOption'
},
}
// ok
const props2: IModalProps = {
isOpen: true,
type: 'basic',
options: {
tag: 'IModalOption'
},
content: null as any as ReactElement
}
// ok
const props3: IModalProps = {
isOpen: true,
type: 'basic',
options: {
tag: 'IModalOption'
},
children: null as any as ReactElement
}
// ok
const props4: IModalProps = {
isOpen: true,
type: 'basic',
options: {
tag: 'IModalOption'
},
children: null as any as ReactElement,
content: null as any as ReactElement
}
Union
utility type distributes content | children
.
It means that it is applied to each union. Union<'content' | 'children'>
returns Record<'content, ReactElement> | Record<'children, ReactElement>
.
In order to achieve desired behavior, you just need to merge base props with union:
type IModalProps = Props & Union<'content' | 'children'>
Upvotes: 1