admin管理员组

文章数量:1200962

I am trying to create a reusable component in reactjs with typescript. I am currently getting this error:

Type '{ children: string; type: string; }' is not assignable to type 'DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>'.
  Type '{ children: string; type: string; }' is not assignable to type 'ButtonHTMLAttributes<HTMLButtonElement>'.
    Types of property 'type' are incompatible.
      Type 'string' is not assignable to type '"button" | "submit" | "reset" | undefined'.  TS2322

     7 | 
     8 | const Button = ({ text, ...otherProps }: IProps) => (
  >  9 |   <button {...otherProps}>
       |    ^
    10 |     { text }
    11 |   </button>
    12 | );

I am pretty new to typescript so I am not sure why I have this error. I think I am not assigning the correct types in my IProps interface in Button.tsx. I am not sure which type to assign

Button.tsx

import React from 'react';

interface IProps {
  text: string,
  type: string
}

const Button = ({ text, ...otherProps }: IProps) => (
  <button {...otherProps}>
    { text }
  </button>
);

export default Button;

How it is currently being used:

<Button type="submit">Sign up</Button>

I am trying to create a reusable component in reactjs with typescript. I am currently getting this error:

Type '{ children: string; type: string; }' is not assignable to type 'DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>'.
  Type '{ children: string; type: string; }' is not assignable to type 'ButtonHTMLAttributes<HTMLButtonElement>'.
    Types of property 'type' are incompatible.
      Type 'string' is not assignable to type '"button" | "submit" | "reset" | undefined'.  TS2322

     7 | 
     8 | const Button = ({ text, ...otherProps }: IProps) => (
  >  9 |   <button {...otherProps}>
       |    ^
    10 |     { text }
    11 |   </button>
    12 | );

I am pretty new to typescript so I am not sure why I have this error. I think I am not assigning the correct types in my IProps interface in Button.tsx. I am not sure which type to assign

Button.tsx

import React from 'react';

interface IProps {
  text: string,
  type: string
}

const Button = ({ text, ...otherProps }: IProps) => (
  <button {...otherProps}>
    { text }
  </button>
);

export default Button;

How it is currently being used:

<Button type="submit">Sign up</Button>
Share Improve this question asked Dec 27, 2019 at 0:54 LiondancerLiondancer 16.5k54 gold badges163 silver badges262 bronze badges
Add a comment  | 

4 Answers 4

Reset to default 12

Using type React.ComponentProps<'button'>) for Button component worked for me.

Typescript already has a definition of the types that are allowed in a button so you have to declare an enum which matches with the available types:

import React from 'react';

enum ButtonTypes {
  "button",
  "submit",
  "reset",
  undefined
} 

interface IProps {
  text: string,
  type: ButtonTypes
}

const Button = ({ text, ...otherProps }: IProps) => (
  <button {...otherProps}>
    { text }
  </button>
);

export default Button;

You can read more on enums here.

You can create your custom reusable component something like this, where you can pass your custom props and as well receive all the button props using ...rest. And now when you use this component you can just simply pass the onClick and even if you now don't specify this prop it will automatically get it, as it can infer all the default button elements props.

The cn is for className, it is a util function that helps us pass new classNames and overwrite the existing ones that makes it more reusable component.

import React from "react";
import { cn } from "@/lib/utils/twMerge";


interface ButtonProps extends 
React.ButtonHTMLAttributes<HTMLButtonElement> {
  className?: string;
  children: React.ReactNode;
 }

const Button = (props: ButtonProps) => {
  const { className, children, ...rest } = props;

  return (
    <button
      className={cn(
        "rounded-[20px] bg-accent-green min-h-[50px] text-[#000000] 
         text-[16px] font-normal font-poppins flex items-center 
        justify-center min-w-[160px] ",
        className
      )}
      {...rest}
    >
      {children}
    </button>
  );
};

export default Button;

Usage:

Here's how you can import/use and pass the type and onClick props without specifying these inside the custom Button Component.

import Button from "@/components/ui/Button";


<Button type="submit" onClick={()=>console.log("Clicked")}>
   Get started
</Button>

Here's how you can create the cn function. It is using two packages "tailwind-merge" and "clsx", so if you want to use this then make sure you install them as well and also create this function like this.

import { twMerge } from "tailwind-merge";
import { clsx, ClassValue } from "clsx";

export const cn = (...inputs: ClassValue[]) => {
  return twMerge(clsx(inputs));
};

Typescript has got type definitions. This also applies to html elements such as buttons, inputs etc. If a reusable component is to be created, e.g "A button component" the type or interface needs to match what has been defined by typescript.

Quick fix in a few lines using an interface for a button element; The button types defined below are the same with what had be defined by typescript.

import React from 'react';
interface IProps {
  text: string,
  type: "button"|"submit"|"reset"|undefined
}

const Button = ({ text, ...otherProps }: IProps) => (
  <button {...otherProps}>
    { text }
</button>
);

export default Button;

This should fix the error message "Typescript with not assignable type error"

本文标签: