Interface is a reserved word when using yarn workspaces, typescript + nextjs + common react component library

Viewed 22

I am trying to create a monorepo (yarn workspaces) with a next.js application and a separate react component library. But when i start the next.js app and try to use any component from the react library i get the error The keyword 'interface' is reserved.

My file structure:

/apps
  /backend <- express server
  /frontend <- next.js
/packages
  /ui
    index.tsx
    /components
      ...
package.json

My package.json files:

/package.json
{
  "name": "monorepo-demo",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "private": "true",
  "workspaces": [
    "packages/**",
    "apps/**"
  ],
  "scripts": {
    "dev:backend": "cd apps/backend && yarn dev",
    "dev:frontend": "cd apps/frontend && yarn dev",
    "dev": "concurrently \"yarn workspace frontend dev\" \"yarn workspace backend dev\""
  },
  "dependencies": {
    "concurrently": "^7.4.0"
  }
}
/apps/frontend/package.json
{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@types/styled-components": "^5.1.26",
    "next": "12.3.0",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-icons": "^4.4.0",
    "styled-components": "^5.3.5",
    "ui": "*"
  },
  "devDependencies": {
    "@types/node": "18.7.16",
    "@types/react": "18.0.18",
    "@types/react-dom": "18.0.6",
    "eslint": "8.23.0",
    "eslint-config-next": "12.3.0",
    "typescript": "4.8.3"
  }
}
/packages/ui/package.json
{
  "name": "ui",
  "version": "0.0.0",
  "private": true,
  "license": "MIT",
  "main": "dist/index.js",
  "files": [
    "components/**/*"
  ],
  "dependencies": {
    "@types/react": "^18.0.18",
    "@types/styled-components": "^5.1.26",
    "config": "*",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "styled-components": "^5.3.5",
    "tsc": "^2.0.4",
    "typescript": "^4.8.3"
  },
  "scripts": {
    "build": "tsc",
    "dev": "tsc -w"
  }
}

Example of next.js page using components

/* /apps/frontend/pages/index.tsx */
import type { NextPage } from "next";
import { Button, Heading } from "ui";
import { BsEmojiSmile } from "react-icons/bs";

const Home: NextPage = () => {
  return (
    <>
      <div>
        <Button small>Small button</Button>
        <Button medium>Medium button</Button>
        <Button big>Big button</Button>
        <Button>No size given (default to medium)</Button>
      </div>

      <div>
        <Button small icon>
          <BsEmojiSmile />
          Small button w/icon
        </Button>
        <Button medium icon>
          <BsEmojiSmile />
          Medium button w/icon
        </Button>
        <Button big icon>
          <BsEmojiSmile />
          Big button w/icon
        </Button>
        <Button icon>
          <BsEmojiSmile />
          No size given (default to medium) w/icon
        </Button>
      </div>

      <div>
        <Heading small>Small heading (h3)</Heading>
        <Heading medium>Medium heading (h2)</Heading>
        <Heading big>Big heading (h1)</Heading>
      </div>
    </>
  );
};

export default Home;

Example of component

/* /packages/ui/components/Button/Button.tsx */
import styled, { css } from "styled-components";

interface Props {
  small?: boolean;
  medium?: boolean;
  big?: boolean;
  icon?: boolean;
}

const Button = styled.button<Props>`
  background: black;
  border: none;
  color: white;
  border-radius: 7px;
  cursor: pointer;
  margin: 20px;

  padding: ${(props) => {
    if (props.small) return "8px 10px";
    if (props.medium) return "12px 18px";
    if (props.big) return "20px 25px";

    return "12px 18px";
  }};

  font-size: ${(props) => {
    if (props.small) return "12px";
    if (props.medium) return "16px";
    if (props.big) return "20px";

    return "16px";
  }};

  // Alternative
  ${(props) =>
    props.small &&
    css`
      padding: 8px 12px;
      font-size: 12px;
    `}

  ${(props) =>
    props.icon &&
    css`
      display: inline-flex;
      column-gap: 12px;
      justify-content: center;
      align-items: center;

      svg,
      i {
        width: 24px;
        height: 24px;
        color: white;
      }
    `}
`;

export default Button;

I have tried just running yarn dev on the frontend project, yarn dev on both frontend and ui. But no luck. Also tried with and without tsc on ui package.

Anyone done something similar with any luck?

Thanks!

0 Answers
Related