0

I am trying to port https://github.com/catalinmiron/react-typical to TypeScript. However, I am facing some issues.

Here's the screenshot with errors in VSCode:

TS project in VSCode

Here's the same code for brevity:

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)

I am unable to write type for Component.

I tried doing the following too:

const Component = React.Component | string

But it says 'Component' refers to a value, but is being used as a type here. Did you mean 'typeof Component'? near return <Component .../> with underline over Component.

I am also unable to convert the typicalRef as typicalRef.current always throws error by showing red squiggly lines under it. Same thing with flat() as well as classNames.join(' ').

I am losing my brain over it. Can't seem to figure it out. Would love any pointers?

4
  • What are the errors shown by VSCode? Also if you just want to ignore them without actually fixing them, add a // @ts-ignore above the lines (although you should try to fix them, of course). Commented Jul 22, 2020 at 14:34
  • have you tried renaming the variable Component to something else? Commented Jul 22, 2020 at 14:35
  • @EmreKoc the 1st error on Component is written in the post. Read the line just below const Component = React.Component | string. I'd love to solve it rather than ignoring it. Commented Jul 22, 2020 at 14:40
  • @FaisalRashid there is no need to rename it something else as neither Component is a reserved keyword or I am destructuring Component from react itself so I think it should be fine even if I rename it :) Commented Jul 22, 2020 at 14:41

3 Answers 3

2

I couldn't solve it using directly as I think TypeScript itself doesn't support it https://github.com/microsoft/TypeScript/issues/28892

But I did solve it using React.createElement syntax. My entire code looks like this right now:

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)
Sign up to request clarification or add additional context in comments.

Comments

0

For the Component part, set it in the props instead of a new variable:

const Typical: React.FC<Props> = ({ wrapper:Component = 'p' }) => {
    return <Component />
}

4 Comments

I've done that already in Props. See the type Props definition. I don't understand what is the difference between my code & yours?
Yours is setting the type of prop, mine is renaming the prop from wrapper to Component, so you can use it as a tag. Basically what you tried to do with the const, without the const.
Ohh got it. But it still gives me error on the return <Component /> saying 'Component' refers to a value, but is being used as a type here. Did you mean 'typeof Component'?ts(2749)
0

I think you have to set your wrapper to React.ComponentType<React.PropsWithRef<any>> which is accurate React type and rename your wrapper directly (do not re-assign in the body that tsc can be confused with mixed type as string) so your code might change as following:

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(' ')} />
}

Since flat method is only available from "es2019" which means you have to include it in the the tsc build by adding to the tsconfig.json following:

"compilerOptions": {
  "lib": ["ES2019"]
},

7 Comments

So the flat() thing worked but I still get the other 3 errors sadly. I did exactly as u said.
What are the 3 others?
the 1st one is the one on the Component, then typicalRef.current says Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.ts(2345) & finally on className={classNames.join(' ')} it says Type 'boolean' is not assignable to type 'string'.ts(2322) on className & on classNames it says The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.ts(2362)
Does it appear after you have changed based on my suggestion? If so, can I see your fully edited code again?
I've just edited to show full my suggestion. You can copy & double check again if your errors get disappeared?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.