How do I type a dynamic tag in React with TypeScript? Given this code:

interface CompProps {
  tag: string;
}

const MyComponent: React.FunctionComponent<CompProps> = ({
  tag = "div",
  children
}) => {
  const Wrapper = tag;

  return <Wrapper>{children}</Wrapper>;
};

I am getting this error:

Type '{ children: ReactNode; }' has no properties in common with type 'IntrinsicAttributes'. ts(2559)

It seems to me I have to add proper types but I cannot figure out which.

2 Answers

0
Doğancan Arabacı On
1
Titian Cernicova-Dragomir On

You can pass in a string as a tag name and use taht as you have, but you need to type it properly to get type checking to work. tag should be a key of JSX.IntrinsicElements.

interface CompProps {
  tag: keyof JSX.IntrinsicElements;
}

const MyComponent: React.FunctionComponent<CompProps> = ({
  tag = "div",
  children
}) => {
  const Wrapper = tag as 'div';

  return <Wrapper>{children}</Wrapper>;
};

You will notice this type assertion: tag as 'div'. The reason this is needed will become apparent if you comment out the type assertion. In theory, the code should work. In practice tsserver will hang using over 2GB or RAM. It's probably trying to check all possible tags and for some reason it hangs doing so, I believe there is a GitHub issue relating to this (The issue I was thinking of is closed, opened one here). The assertions trick will make it only check for div which is close enough.

This performance issue only occurs on 3.4 and higher. In 3.3 it works without the assertion.