Условный тип на основе значения другого реквизита

В моем проекте у меня есть компонент, который принимает два реквизита:

collapsible,
onToggle

Я изо всех сил пытаюсь создать тип для этих реквизитов в TypeScript. Проблема в том, что когда сворачиваемый true, я хочу, чтобы функция onToggle была (): void, но если сворачиваемый false, я хочу, чтобы onToggle не был определен.

Я пробовал что-то вроде этого:

type Props = {
  collapsible: boolean;
  onToggle: collapsible ? () => void : undefined;
}

Но, очевидно, это не работает, поскольку складной объект не определен при определении типа onToggle. Как с этим быть? Возможно ли, чтобы типы зависели от значений?


person Tomasz Staszkiewicz    schedule 09.06.2020    source источник
comment
вам действительно нужно collapsible? Нельзя ли сделать onToggle необязательным и проверить, есть ли onToggle === undefined?   -  person Ayush Gupta    schedule 09.06.2020
comment
Хотя это вполне выполнимо, используя размеченное объединение на логической опоре, поскольку в ответе ниже вы на самом деле слишком многого требуете от системы типов. Представьте, что у вас есть collapsible: Math.random() > .5   -  person Yury Tarabanko    schedule 09.06.2020
comment
Это был более общий вопрос, возможно ли вообще что-то подобное. Я знаю, что в этом случае легко просто проверить это внутри компонента :)   -  person Tomasz Staszkiewicz    schedule 09.06.2020


Ответы (2)


Вы можете использовать размеченный союз (размеченный на collapsible):

type Props = {
    common?: string
} & ({
    collapsible?: false;
} | {
    collapsible: true;
    onToggle: () => void
    })

function Test(p: Props) {
    return <></>
}

function Usage() {
    return <>
        <Test /> {/* Ok */}
        <Test collapsible={false} /> {/* Ok */}
        <Test collapsible={true} /> {/* Err, as expected */}
        <Test collapsible={true} onToggle={() => { }} /> {/* ok */}
    </>
}

Ссылка на игровую площадку

person Titian Cernicova-Dragomir    schedule 09.06.2020

Ваша складная опора имеет логический тип, поэтому она будет либо ложной/истинной,

Разве ты не можешь сделать что-то подобное,

    type Props = {
     collapsible: boolean;
     onToggle():void | undefined;
   }

OR,

      type Props = {
         collapsible: boolean;
         onToggle?():void;
       }

И тогда во время реализации вы можете легко проверить, является ли onToggle неопределенным или нет. Потому что если что-то является необязательным и не предусмотрено, то оно по умолчанию не определено в TS.

person Mohit    schedule 09.06.2020