본문으로 바로가기
728x90

공통으로 사용되는 타입과 Spreading attributes를 사용할 때 어떻게 하면 좋을까 알아보다 좋은 포스팅이 있었다.

 

WithChildren helper type

type WithChildren<T = {}> = 
  T & { children?: React.ReactNode };

type CardProps = WithChildren<{
  title: string;
}>;
// works as well
type CardProps = { title: string } & WithChildren;

 

Preset attributes

type ButtonProps =
  Omit<JSX.IntrinsicElements["button"], "type">;

function Button({ ...allProps }: ButtonProps) {
  return <button type="button" {...allProps} />;
}

// 💥 This breaks, as we omitted type
const z = <Button type="button">Hi</Button>;

 

Styled components

type StyledButton = Omit<
  JSX.IntrinsicElements["button"],
  "type" | "className"
> & {
  type: "primary" | "secondary";
};

function StyledButton({ type, ...allProps }: StyledButton) {
  return <Button className={`btn-${type}`} />;
}

 

Required properties

type MakeRequired<T, K extends keyof T> = Omit<T, K> &
  Required<{ [P in K]: T[P] }>;
type ImgProps 
  = MakeRequired<
    JSX.IntrinsicElements["img"], 
    "alt" | "src"
  >;

export function Img({ alt, ...allProps }: ImgProps) {
  return <img alt={alt} {...allProps} />;
}

const zz = <Img alt="..." src="..." />;

 

Controlled Input

기본으로 empty string을 주고 싶다면 다음과 같은 type을 이용해보자.

type ControlledProps =
  Omit<JSX.IntrinsicElements["input"], "value"> & {
    value?: string;
  };
function Controlled({
  value = "", onChange, ...allProps
}: ControlledProps) {
  const [val, setVal] = useState(value);
  return (
    <input
      value={val}
      {...allProps}
      onChange={e => {
        setVal(() => e.target?.value);
        onChange && onChange(e);
      }}
    />
  );
}

 

 

https://fettblog.eu/typescript-react-component-patterns/#preset-attributes

 

TypeScript + React: Component patterns

This list is a collection of component patterns for React when working with TypeScript. See them as an extension to the TypeScript + React Guide that deals with overall concepts and types. This list has been heavily inspired by chantastic’s original Reac

fettblog.eu