1

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.

2 Answers 2

1
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'>

Playground

Sign up to request clarification or add additional context in comments.

2 Comments

thanks, how can I access property? like const fnA = (e : IModalProps) => { const aa = e.children } ;
In order to access it, you should check whether property children exists or not with help od conditional statement of custom typeguard. typescriptlang.org/docs/handbook/… . Please see hasProperty typeguard in my blog catchts.com/FP-style#fp_utils
1

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;
    // ...
}

2 Comments

how can I access property? like const fnA = (e : IModalProps) => { const aa = e.children } ;
To use it, you need to check if the property exists in the type, do something like const content = 'children' in props ? props.children : props.content;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.