【问题标题】:TypeScript can't infer generic type when T is conditional当 T 有条件时,TypeScript 无法推断泛型类型
【发布时间】:2020-10-21 07:39:36
【问题描述】:

我正在尝试编写一个 React 组件,它的属性会根据泛型属性的类型而变化。

interface PropsBase<T> {
  value: T;
  children: (value: T) => ReactElement;
}

type ArrayType<T extends any[]> = T extends Array<infer U> ? U : never;

interface ArrayProps<T extends any[]> extends Omit<PropsBase<T>, 'children'> {
  children: (value: ArrayType<T>, index: number, array: T) => ReactElement;
}

type Props<T> = T extends any[] ? ArrayProps<T> : PropsBase<T>;

const MyComp = <T extends any>({ value, children }: Props<T>) => {
  if (Array.isArray(value)) {
    return <>{value.map(children)}</>;
  }
  
  return <div>{children(value)}</div>;
};

如果value 是一个数组,那么它所期望的子元素是一个应用于数组中每个元素的函数。否则它需要一个只接受值的函数。

由于我尚未确定的原因,当Props 如上所述是有条件的时,它无法确定T 的类型。

const val = { a: 10 };
const rendered = 
  <MyComp value={val}>
    {value => <span>{value.a}</span>}
  </MyComp>;

// error: Object is of type 'unknown'.

即使三元运算符的两个结果相同也是如此。

type Props<T> = T extends any[] ? PropsBase<T> : PropsBase<T>;
// same error

任何其他道具,包括仅在ArrayProps 中列出的道具都被正确推断。

interface ArrayProps<T extends any[]> extends Omit<PropsBase<T>, 'children'> {
  children: (value: ArrayType<T>, index: number, array: T) => ReactElement;
  arrayOpt: boolean;
}

const array = [ 1, 2, 3 ];
const renderedArray =
  <MyComp value={array} arrayOpt>
    {value => <span>{value}</span>}
  </MyComp>;

如果我不得不猜测,这是 tsc 中的一个错误。同时,有没有办法解决这个问题?

TS Playground

【问题讨论】:

    标签: reactjs typescript


    【解决方案1】:

    这很乱,但我找到了解决方法。

    interface MyComp<T> extends FunctionComponent<Props<T>> {};
    function MyComp<T extends any[]>(props: ArrayProps<T>): ReactElement;
    function MyComp<T>(props: PropsBase<T>): ReactElement;
    function MyComp<T>(props: Props<T>) {
      const {
        value,
        children,
        arrayOpt,
      } = props as PropsBase<T> & { arrayOpt: boolean };
    
      if (Array.isArray(value)) {
        return <>{value.map(children)}</>;
      } else {
        return <div>{(children as PropsBase<T>['children'])(value)}</div>;
      }
    };
    

    TS Playground

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-17
      • 1970-01-01
      • 2017-10-04
      • 2016-12-05
      • 2020-09-22
      • 1970-01-01
      • 2018-01-18
      相关资源
      最近更新 更多