简体   繁体   English

Typescript 根据参数值进行条件扩展

[英]Typescript conditional extends based on parameters value

I'm quite new to Typescript and I'm trying to have a conditional extends based on a function argument value.我对 Typescript 很陌生,我正在尝试基于 function 参数值进行条件扩展。 The context is to define a widget for object selection that can be a select, a list of radio (a radio group) or a list of checkbox (a checkbox group).上下文是为 object 选择定义一个小部件,它可以是 select、单选列表(单选组)或复选框列表(复选框组)。 Each of this different widget accept different props, name: SelectProps , RadioGroupProps and CheckboxGroupProps .每个不同的小部件都接受不同的道具,名称: SelectPropsRadioGroupPropsCheckboxGroupProps The widget selection is based on two parameters: expand (means we want a list of checkbox or radio) and multiple (means we want to select multiple elements or not).小部件选择基于两个参数: expand (意味着我们想要一个复选框或单选列表)和multiple (意味着我们想要 select 多个元素或不)。

function SelectionWidget(props: SelectionWidgetProps) {}

Here, I want that:在这里,我想要:
if props matches {expand: true, multiple: false} then SelectionWidgetProps must extends RadioGroupProps .如果props匹配{expand: true, multiple: false}那么SelectionWidgetProps必须扩展RadioGroupProps
if props matches {expand: true, multiple: true} then SelectionWidgetProps must extends CheckboxGroupProps .如果props匹配{expand: true, multiple: true}SelectionWidgetProps必须扩展CheckboxGroupProps
otherwise, SelectionWidgetProps must extends SelectProps .否则, SelectionWidgetProps必须扩展SelectProps

I tried the following:我尝试了以下方法:

type SelectTypeExtend<T> = 
    T extends { expand: false } ? SelectProps : 
    T extends { expand: true; multiple: false } ? RadioGroupProps :
    T extends { expand: true; multiple: true; } ? CheckboxGroupProps :
    never;

interface SelectTypeProps extends SelectTypeExtends {
    multiple?: boolean;
    expand?: boolean;
}

But it doesn't work as SelectTypeExtends expects an argument.但它不起作用,因为SelectTypeExtends需要一个参数。 Is it possible to achieve this with Typescript?是否可以使用 Typescript 实现这一目标? Thanks!谢谢!

You can extend interface only with statically known types.您只能使用静态已知类型扩展interface It means that does not allow you to extend SelectTypeProps with SelectTypeExtends because SelectTypeExtends is a black box.这意味着不允许您使用SelectTypeExtends扩展SelectTypeProps ,因为SelectTypeExtends是一个黑盒子。 Nobody know type of T .没有人知道T的类型。

In order to manage this case, you should use type instead of interface :为了管理这种情况,您应该使用type而不是interface

type SelectProps = {
  tag: 'SelectProps'
}

type RadioGroupProps = {
  tag: 'RadioGroupProps'
}

type CheckboxGroupProps = {
  tag: 'CheckboxGroupProps '
}

type SelectTypeExtend<T> =
  T extends { expand: false } ? SelectProps :
  T extends { expand: true; multiple: false } ? RadioGroupProps :
  T extends { expand: true; multiple: true; } ? CheckboxGroupProps :
  never;

type SelectTypeProps<T> = { // <------ type instead of interface
  multiple?: boolean;
  expand?: boolean;
} & SelectTypeExtend<T>

Example with react components:带有反应组件的示例:

import React from "react";

import {
  Select,
  SelectProps,
  Checkbox,
  CheckboxGroupProps,
  Radio,
  RadioGroupProps
} from "formik-antd";


export type SelectionComponentProps =
  | { expand?: false } & { options: SelectProps }
  | { expand: true; multiple?: false } & { options: RadioGroupProps }
  | { expand: true; multiple: true } & { options: CheckboxGroupProps };

function SelectionComponent(props: SelectionComponentProps) {
  if (props.expand) {
    if (props.multiple) {
      return <Checkbox.Group {...props.options} />;
    } else {
      return <Radio.Group {...props.options} />;
    }
  }
  return <Select {...props.options} />;
};

const select: SelectProps = 'unimplemented' as any;
const radio: RadioGroupProps = 'unimplemented' as any;
const checkbox: CheckboxGroupProps = 'unimplemented' as any;

export const TestRadio = () => {
  // Accept properties from RadioGroupProps but not from SelectProps or CheckboxGroupProps
  return [
    <SelectionComponent expand options={radio} />, // ok
    <SelectionComponent expand options={select} />, // expected error
    <SelectionComponent expand options={checkbox} />, // expected error
  ]
};

export const TestCheckbox = () => {
  // Accept properties from CheckboxProps but not from SelectProps or RadioGroupProps
  return [
    <SelectionComponent expand multiple options={checkbox} />, // ok
    <SelectionComponent expand multiple options={select} />, // expected error
    <SelectionComponent expand multiple options={radio} /> // expected error
  ]
};

export const TestSelect = () => {
  // Accept properties from SelectProps but not from RadioGroupProps or CheckboxGroupProps
  return [
    <SelectionComponent options={select} />, // ok
    <SelectionComponent options={radio} />, // expected error
    <SelectionComponent options={checkbox} />, // expected error
  ]
};

Playground操场

I have slightly modified SelectionComponentProps type.我稍微修改了SelectionComponentProps类型。 Please keep in mind, that if you don't provide some property to react component, TS treats it as undefined and not as false , hence you need to make some of your false properties as a partial请记住,如果您不提供一些属性来响应组件,TS 会将其视为undefined而不是false ,因此您需要将一些false属性设为partial

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM