reactjs - Typescript:排除部分中提供的属性

标签 reactjs typescript

我编写了一个名为 withDefaults 的函数它接受一个 React 组件(实际上是一个函数)并提供一个具有默认参数值的对象。它返回一个函数,该函数调用原始 React 组件(函数)并将默认参数与最终参数集合并。

当默认集中提供了所需参数时,如何使这些参数不再需要?

function withDefaultProps<C extends React.ElementType>(Component: c) {
  const ResultComponent = Component as React.FunctionComponent;
  return (
    (defaultProps: Partial<React.ComponentProps<C>>) => (
      (finalProps: React.ComponentProps<C>) => (
        <ResultComponent {...defaultProps} {...finalProps}>
          {finalProps.children}
        </ResultComponent>
      )
    )
  )
}

例如,我有一个组件需要 ab作为属性。

type MyCompProps = {
  a: string,
  b: string
};

function MyComp(props: MyCompProps) {
  return null; // My react structure here
}

const MyPrefilledComp = withDefaultProps(MyComp)({ a: 'alwaysThisString' });

这里是 Typescript 错误出现的地方。当我尝试使用MyPrefilledComp时它仍然要求我提供 a属性,即使它有默认值。我该如何调整我的withDefaulProps方法使其可选,而不使所有属性可选。我已经尝试过使用 keyOf 进行 Diff 和 Omit,但我的 Typescript 非常初级,所以我可能做错了。

// Typescript error: Property a is required
function MyApp() {
  return (
    <MyPrefilledComp b="a non default value" />
  )
}

我尝试简化它,并且可以轻松地看出问题出在哪里,我只是不确定如何解决它。类似:Omit<OriginalProps, Partial<OriginalProps>>但该部分根据调用被赋予动态类型。

function withDefaults(defaultProps: Partial<OriginalProps>) {
  return function wrapper(finalProps: OriginalProps) {
    return {
      ...defaultProps,
      ...finalProps
    };
  }
}

最佳答案

我倾向于写你的 withDefaults()最后的函数是这样的:

const makeWithDefaults = <T,>() =>
    <K extends keyof T>(defaultProps: Pick<T, K>) =>
        (finalProps: Partial<Pick<T, K>> & Omit<T, K>) =>
            ({ ...defaultProps, ...finalProps }) as T;

type MyCompProps = {
    a: string,
    b: string
};

const withDefaults = makeWithDefaults<MyCompProps>();

请注意makeWithDefaults()除了返回一个函数之外,在运行时没有做太多事情,但在编译时你可以使用泛型参数 T指定您要构建的实际对象类型。

它返回的函数使用实用程序类型 Pick<T, K> , Partial<T> ,和 Omit<T, K> .

一次T指定后,withDefaults()函数将接受 defaultProps具有来自 T 的任何属性子集的对象,并会推断 K成为这个defaultProps的 key 目的。返回的函数接受 finalProps类型 Partial<Pick<T, K>> & Omit<T, K>Omit<T, K>部分说 finalProps 必须具有 T 中的所有属性defaultProps 中缺少哪些内容,以及Partial<Pick<T, K>>部分说 finalProps 可能具有 T 中的任何属性包含在 defaultProps 中。该函数的返回类型为 asserted为原创T (这应该是真的,但编译器无法验证它)。


让我们看看它是否有效:

const hasDefaultA = withDefaults({ a: "hello" });

const foo = hasDefaultA({ b: "works" });
console.log(JSON.stringify(foo)); // {"a":"hello","b":"works"}
const bar = hasDefaultA({}); // error! property b missing
const baz = hasDefaultA({ a: "goodbye", b: "works" });
console.log(JSON.stringify(baz)); // { "a": "goodbye", "b": "works" }

看起来不错。我没有具体的reactjs经验,所以我会听从其他人关于如何制作你的withDefaultProps()的信息。版本工作。

Playground link to code

关于reactjs - Typescript:排除部分中提供的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64920960/

相关文章:

javascript - 在子组件的状态之间共享父状态?

reactjs - react + Redux : Scrolling a DOM element after state change

模块使用者的 TypeScript 声明合并

javascript - Angular 2 中的弹出对话框

javascript - Jasmine 测试用例未在已编译的 Typescript 中定义内启动

android - React Native - 从android内容uri获取文件名

javascript - 是否可以在功能组件之外使用 React Hooks,或者我必须使用 mobx 或 redux?

javascript - 我如何在reactjs中为日历中的特定日期提供颜色

Angular 订阅。无法获取数据

typescript - 访问对象中的可选键,其中键是文字联合类型中的文字,没有错误 "Object is possibly ' 未定义'"