将通用 React 组件转换为 TypeScript 会抛出错误
Converting a generic React Component to TypeScript throws error
我正在尝试将 https://github.com/catalinmiron/react-typical 移植到 TypeScript。但是,我遇到了一些问题。
这是 VSCode 中有错误的屏幕截图:
为简洁起见,下面是相同的代码:
import React from 'react'
import { type, type as loopedType } from '@camwiegert/typical'
import styles from './styles.module.css'
type Props = {
steps: Array<any>
loop: number
className: string
wrapper: React.Component
}
const Typical: React.FC<Props> = ({ steps, loop, className, wrapper = 'p' }) => {
const typicalRef = React.useRef<HTMLElement>(null)
const Component: string = wrapper
const classNames: string[] = [styles.typicalWrapper]
if (className) {
classNames.unshift(className)
}
React.useEffect(() => {
if (loop === Infinity) {
type(typicalRef.current, ...steps, loopedType)
} else if (typeof loop === 'number') {
type(typicalRef.current, ...Array(loop).fill(steps).flat())
} else {
type(typicalRef.current, ...steps)
}
}, [typicalRef])
return <Component ref={typicalRef} className={classNames.join(' ')} />
}
export default React.memo(Typical)
我无法为 Component
写字。
我也尝试过以下操作:
const Component = React.Component | string
但是它在 return <Component .../>
附近显示 'Component' refers to a value, but is being used as a type here. Did you mean 'typeof Component'?
,在 Component
上方有下划线。
我也无法转换 typicalRef
,因为 typicalRef.current
总是通过在其下方显示红色波浪线来抛出错误。 flat()
和 classNames.join(' ')
.
也一样
我为此失去了理智。似乎无法弄清楚。想要任何指示吗?
对于组件部分,在道具中设置它而不是新变量:
const Typical: React.FC<Props> = ({ wrapper:Component = 'p' }) => {
return <Component />
}
我认为你必须将你的 wrapper
设置为 React.ComponentType<React.PropsWithRef<any>>
这是准确的 React 类型并直接重命名你的包装器(不要在正文中重新分配 tsc
可以是与混合类型混淆为字符串),因此您的代码可能会更改如下:
type Props = {
steps: Array<any>
loop: number
className: string
wrapper: React.ComponentType<React.PropsWithRef<any>>
}
const Typical: React.FC<Props> = ({ steps, loop, className, wrapper: Component = 'p' }) => {
const typicalRef = React.useRef<HTMLElement>()
const classNames: string[] = [styles.typicalWrapper]
if (className) {
classNames.unshift(className)
}
React.useEffect(() => {
if (loop === Infinity) {
type(typicalRef.current, ...steps, loopedType)
} else if (typeof loop === 'number') {
type(typicalRef.current, ...Array(loop).fill(steps).flat())
} else {
type(typicalRef.current, ...steps)
}
}, [typicalRef])
return <Component ref={typicalRef} className={classNames.join(' ')} />
}
因为 flat
方法仅适用于“es2019”,这意味着您必须通过添加到 tsconfig.json
以下内容来将其包含在 tsc
构建中:
"compilerOptions": {
"lib": ["ES2019"]
},
我无法直接使用它来解决它,因为我认为 TypeScript 本身不支持它 https://github.com/microsoft/TypeScript/issues/28892
但我确实使用 React.createElement
语法解决了它。我的整个代码现在看起来像这样:
import React from 'react'
import { type, type as loopedType } from '@camwiegert/typical'
import styles from './styles.module.css'
type Props = {
steps: Array<any>
loop: number
className?: string
wrapper: keyof JSX.IntrinsicElements
} & React.HTMLAttributes<HTMLOrSVGElement>
const Typical = ({ steps, loop, className, wrapper: Wrapper = 'p' }: Props) => {
const typicalRef: React.RefObject<HTMLElement> = React.useRef<HTMLElement>(null)
const classNames: string[] = [styles.typicalWrapper]
if (className) {
classNames.unshift(className)
}
const typicalStyles: string = classNames.join(' ')
React.useEffect(() => {
if (loop === Infinity) {
type(typicalRef.current as HTMLElement, ...steps, loopedType)
} else if (typeof loop === 'number') {
type(typicalRef.current as HTMLElement, ...Array(loop).fill(steps).flat())
} else {
type(typicalRef.current as HTMLElement, ...steps)
}
}, [typicalRef])
return React.createElement(Wrapper, {
ref: typicalRef,
className: typicalStyles,
})
}
export default React.memo(Typical)
我正在尝试将 https://github.com/catalinmiron/react-typical 移植到 TypeScript。但是,我遇到了一些问题。
这是 VSCode 中有错误的屏幕截图:
为简洁起见,下面是相同的代码:
import React from 'react'
import { type, type as loopedType } from '@camwiegert/typical'
import styles from './styles.module.css'
type Props = {
steps: Array<any>
loop: number
className: string
wrapper: React.Component
}
const Typical: React.FC<Props> = ({ steps, loop, className, wrapper = 'p' }) => {
const typicalRef = React.useRef<HTMLElement>(null)
const Component: string = wrapper
const classNames: string[] = [styles.typicalWrapper]
if (className) {
classNames.unshift(className)
}
React.useEffect(() => {
if (loop === Infinity) {
type(typicalRef.current, ...steps, loopedType)
} else if (typeof loop === 'number') {
type(typicalRef.current, ...Array(loop).fill(steps).flat())
} else {
type(typicalRef.current, ...steps)
}
}, [typicalRef])
return <Component ref={typicalRef} className={classNames.join(' ')} />
}
export default React.memo(Typical)
我无法为 Component
写字。
我也尝试过以下操作:
const Component = React.Component | string
但是它在 return <Component .../>
附近显示 'Component' refers to a value, but is being used as a type here. Did you mean 'typeof Component'?
,在 Component
上方有下划线。
我也无法转换 typicalRef
,因为 typicalRef.current
总是通过在其下方显示红色波浪线来抛出错误。 flat()
和 classNames.join(' ')
.
我为此失去了理智。似乎无法弄清楚。想要任何指示吗?
对于组件部分,在道具中设置它而不是新变量:
const Typical: React.FC<Props> = ({ wrapper:Component = 'p' }) => {
return <Component />
}
我认为你必须将你的 wrapper
设置为 React.ComponentType<React.PropsWithRef<any>>
这是准确的 React 类型并直接重命名你的包装器(不要在正文中重新分配 tsc
可以是与混合类型混淆为字符串),因此您的代码可能会更改如下:
type Props = {
steps: Array<any>
loop: number
className: string
wrapper: React.ComponentType<React.PropsWithRef<any>>
}
const Typical: React.FC<Props> = ({ steps, loop, className, wrapper: Component = 'p' }) => {
const typicalRef = React.useRef<HTMLElement>()
const classNames: string[] = [styles.typicalWrapper]
if (className) {
classNames.unshift(className)
}
React.useEffect(() => {
if (loop === Infinity) {
type(typicalRef.current, ...steps, loopedType)
} else if (typeof loop === 'number') {
type(typicalRef.current, ...Array(loop).fill(steps).flat())
} else {
type(typicalRef.current, ...steps)
}
}, [typicalRef])
return <Component ref={typicalRef} className={classNames.join(' ')} />
}
因为 flat
方法仅适用于“es2019”,这意味着您必须通过添加到 tsconfig.json
以下内容来将其包含在 tsc
构建中:
"compilerOptions": {
"lib": ["ES2019"]
},
我无法直接使用它来解决它,因为我认为 TypeScript 本身不支持它 https://github.com/microsoft/TypeScript/issues/28892
但我确实使用 React.createElement
语法解决了它。我的整个代码现在看起来像这样:
import React from 'react'
import { type, type as loopedType } from '@camwiegert/typical'
import styles from './styles.module.css'
type Props = {
steps: Array<any>
loop: number
className?: string
wrapper: keyof JSX.IntrinsicElements
} & React.HTMLAttributes<HTMLOrSVGElement>
const Typical = ({ steps, loop, className, wrapper: Wrapper = 'p' }: Props) => {
const typicalRef: React.RefObject<HTMLElement> = React.useRef<HTMLElement>(null)
const classNames: string[] = [styles.typicalWrapper]
if (className) {
classNames.unshift(className)
}
const typicalStyles: string = classNames.join(' ')
React.useEffect(() => {
if (loop === Infinity) {
type(typicalRef.current as HTMLElement, ...steps, loopedType)
} else if (typeof loop === 'number') {
type(typicalRef.current as HTMLElement, ...Array(loop).fill(steps).flat())
} else {
type(typicalRef.current as HTMLElement, ...steps)
}
}, [typicalRef])
return React.createElement(Wrapper, {
ref: typicalRef,
className: typicalStyles,
})
}
export default React.memo(Typical)