typescript 导出时隐藏通用类型属性

iih3973s  于 2023-02-25  发布在  TypeScript
关注(0)|答案(1)|浏览(153)

我有一小组组件,其中Wrapper将通过cloneElement向每个子组件注入一个prop来操作它的children(因此称为Component)。这里的问题是Component prop是泛型类型。当我在代码中公开Component时,我不希望它的某个prop出现在签名中。因为它将由Wrapper组件自动注入。我有一个简明的例子来说明我的意思:
types.ts

export type SomeObject = {
  someKey: string;
};

type PropThatWillBeInjected<T extends SomeObject> = {
  fn: (value: string) => T;
};

export type WannaBePropTypes = {
  name: string;
};

export type PropTypes<T extends SomeObject> = PropThatWillBeInjected<T> &
  WannaBePropTypes;

重要提示:PropTypes<T>Component所期望的,但是作为一个程序员,我希望WannaBePropTypes是这个组件的签名。
x1米11米1x

function Component<T extends SomeObject>(props: PropTypes<T>) {
  const { fn, name } = props;
  const result = fn(name);
  return <div>Hello, {result.someKey}</div>;
}

export default Component;

Wrapper.tsx

function Wrapper(props: { children: ReactNode }) {
  const { children } = props;
  return (
    <div id="wrapper">
      {React.Children.map(
        children as ReactElement<PropTypes<SomeObject>>,
        (child, index) =>
          cloneElement(child, {
            ...child.props,
            fn: (value: string) => ({
              someKey: `${value}-${index}`,
            }),
          })
      )}
    </div>
  );
}

export default Wrapper;

正如预期的那样,当我尝试如下使用这些组件时,代码可以工作,但编译器会抱怨:

<Wrapper>
  <Component name="Alice" />
  <Component name="Bob" />
</Wrapper>

类型"{name:}"中缺少属性"fn"字符串;}",但在类型" PropThatWillBeInjected "中是必需的。(2741)
有没有办法强制转换Component,这样我就不需要手动传递fn了?我知道当 prop 类型不是泛型的时候有办法...
我尝试过的:
1.将fn设置为可选:有效,但这不是我想要的解决方案;
1.用另一个组件 Package Component并将noop传递到Component:工作,但我不想创建这个不必要的 Package 器;
具有以下示例代码的Playground:StackBlitz

thtygnil

thtygnil1#

如果我没理解错的话,您希望将Component作为<Component name="Alice" />调用,并且应该存在针对以下两种情况的内部逻辑:当fn被传递时,如果是这样,你可以创建不必要的类型(而不是不必要的 Package 器),它将是WannaBePropTypes或完整的属性之一。这就像你的try#1和try#2的某种组合:

type FullProps<T extends SomeObject> = PropThatWillBeInjected<T> & WannaBePropTypes;

type PropTypes<T extends SomeObject> = FullProps<T> | WannaBePropTypes;

因此,在Wrapper组件中定义children as ReactElement<FullProps<SomeObject>>之前,fn是可选的。
至于Component,我想你可以直接给FullProps投 prop :

const { fn, name } = props as FullProps<T>;

但是如果出于某种原因需要更严格的代码,可以这样缩小props类型:

function isFullProps<T extends SomeObject>(props: PropTypes<T>): props is FullProps<T> {
    return !!(props as FullProps<T>).fn;
}

function Component<T extends SomeObject>(props: PropTypes<T>) {
    if (!isFullProps(props)) return <></>;
    const { fn, name } = props;
    const result = fn(name);
    return <div>Hello, {result.someKey}</div>;
}

尽管看起来这个条件在你的情况下总是假的。
这是 * 如何处理仅使用Typescript *。
顺便说一句:也许你可以把WannaBePropTypes对象的数组传递给Wrapper而不是子对象?如果<Component name="Alice" />本身什么也不做,这听起来会更好。

相关问题