【问题标题】:Converting React Higher Order Component (HOC) to TypeScript Causes Error: "Exported variable has or is using private name"将 React 高阶组件 (HOC) 转换为 TypeScript 会导致错误:“导出的变量具有或正在使用私有名称”
【发布时间】:2021-02-19 05:06:50
【问题描述】:

向 TypeScript 专家寻求帮助,我在尝试将 React 高阶组件 (HOC) 重写为 TS 时遇到了错误。我不确定如何解决这个问题。

“src/withEnv.tsx(15,14): 错误 TS4025: 导出的变量 'withEnv' 已经或正在使用私有名称 'WithEnv'。”

我的代码 -

import * as React from 'react'
import Context from './context'
import hoistNonReactStatic from 'hoist-non-react-statics'

function getDisplayName(WrappedComponent) {
  return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}

function defaultEnvToProps(context) {
  return {
    env: context,
  }
}

const withEnv = (mapper) => (Component) => {
  class WithEnv extends React.Component {
    static displayName: string
    render() {
      return (
        <Context.Consumer>
          {(context) => {
            const props = Object.assign(
              {},
              typeof mapper === 'function'
                ? mapper(context)
                : defaultEnvToProps(context),
              this.props
            )
            return <Component {...props} />
          }}
        </Context.Consumer>
      )
    }
  }
  WithEnv.displayName = WithEnv(${getDisplayName(Component)})
  hoistNonReactStatic(WithEnv, Component)
  return WithEnv
}

export default withEnv

【问题讨论】:

  • 您使用的是哪个 TypeScript 版本?另外,你能分享你的tsconfig.json吗? sn-p 在使用 TypeScript 4.1.2 的 CodeSandbox 的 React Typescript 模板中有效(在将缺少的反引号添加到 withEnv.displayName = ... 之后)。
  • 这里缺少很多信息以便正确输入。 Context 的值是什么类型? mapper 总是只返回一个 env 道具,还是有时会返回其他道具?
  • 这是一个开始:tsplay.dev/4w1z2N 导出导致与github.com/microsoft/TypeScript/issues/6307 相关的问题

标签: reactjs typescript higher-order-components


【解决方案1】:

有很多信息可以正确输入。您的问题中缺少某些信息,例如上下文值的类型,因此我尝试填写空白。

我可以解释您担心的主要错误并告诉您如何解决它。

“src/withEnv.tsx(15,14): error TS4025: Exported variable 'withEnv' has or is using private name 'WithEnv'."

a discussion on GitHub 会告诉你更多关于这个问题的信息。 Typescript 窒息,因为它想将您的 withEnv HOC 的返回类型描述为 WithEnv 私有类。但是声明文件不会包含这个类,因为它只存在于你的函数内部,所以它不能用作返回类型。为了避免错误,您可以手动键入 withEnv 的返回类型作为采用特定道具集的某些组件。

import * as React from 'react'
import { ComponentType } from 'react';
import hoistNonReactStatic from 'hoist-non-react-statics'

type ContextValue = {} // what is this ??????

declare const Context: React.Context<ContextValue>;

function getDisplayName(WrappedComponent: ComponentType<any>): string {
  return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}

function defaultEnvToProps(context: ContextValue): { env: ContextValue } {
  return {
    env: context,
  }
}

// define a type for a function that maps your context to props
type Mapper<Return> = (context: ContextValue) => Return;

// generic type `MappedProps` describes the props returned by the mapper
// default value for `MappedProps` type matches `defaultEnvToProps`
export const withEnv = <MappedProps extends {} = { env: ContextValue }>(
  // mapper is an optional function that maps from the context value to the added props
  mapper?: Mapper<MappedProps>
) =>
  // returned function is generic depending on the component props
  <Props extends {}>(
    // takes a component which uses the added props
    Component: ComponentType<MappedProps & Omit<Props, keyof MappedProps>>
    // returns a component which doesn't need those props
  ): ComponentType<Omit<Props, keyof MappedProps>> => {
    // you could just as well use a function component here and use `useContext`
    class WithEnv extends React.Component<Omit<Props, keyof MappedProps>> {
      static displayName: string;
      render() {
        return (
          <Context.Consumer>
            {(context) => {
              const mappedProps = mapper ? mapper(context) : defaultEnvToProps(context);
              return (
                <Component
                  {...this.props}
                  {...mappedProps as MappedProps} // this assertion is only necessary is `mapper` is optional
                />
              )
            }}
          </Context.Consumer>
        )
      }
    }
    WithEnv.displayName = `WithEnv(${getDisplayName(Component)})`;
    hoistNonReactStatic(WithEnv, Component);
    return WithEnv;
  }

Typescript Playground Link

【讨论】:

    猜你喜欢
    • 2017-02-23
    • 2017-02-09
    • 2019-06-28
    • 2020-02-06
    • 2019-05-10
    • 2020-02-20
    • 2018-09-14
    • 2020-05-19
    • 2020-11-01
    相关资源
    最近更新 更多