aotoyae

[TS/React] children & Props & Hook 타입 본문

TypeScript

[TS/React] children & Props & Hook 타입

aotoyae 2024. 3. 7. 18:17

 

 

💡 Props 의 타입들을 정해보자.

 

button.tsx

import { ReactNode } from 'react';
import styles from './Button.module.css';

interface Props {
  className?: string;
  id?: string;
  children?: ReactNode;
  onClick: any;
}

export default function Button({
  className = '',
  id,
  children,
  onClick,
}: Props) {
  const classNames = `${styles.button} ${className}`;
  return (
    <button className={classNames} id={id} onClick={onClick}>
      {children}
    </button>
  );
}

 

❗️ children: ReactNode ❗️

 

App.tsx

 <Input
        id="password"
        name="password"
        type="password"
        placeholder={t('password')}
        value={values.password}
        onChange={handleChange}
      />

 

input 의 프롭들도 타입을 정해주려는데 너무 많다면?!

HTMLAttributes 를 활용한다!

import { InputHTMLAttributes } from 'react';
import styles from './Input.module.css';

interface Props extends InputHTMLAttributes<HTMLInputElement> {}

export default function Input({ className = '', ...rest }: Props) {
  const classNames = `${styles.input} ${className}`;
  return <input className={classNames} {...rest} />;
}

 

props 의 타입들을 상속 받아 쓸 수 있다!

 

💡 Hook 들의 타입을 정해보자.

✳️ useState

 const [values, setValues] = useState({
    username: '',
    password: '',
  });

 

위 코드의 경우 초기값 때문에 타입이 잘 추론되고 있다.

하지만 더 명시적으로 하고싶다면 아래처럼 제네릭에 타입을 적어준다.

  const [values, setValues] = useState<{ username: string; password: string }>({
    username: '',
    password: '',
  });

 

 

😲 무조건 타입을 정해줘야 하는 경우는 ?

const [names, setNames] = useState([]);

 

빈 배열을 초기값으로 써서 추론이 안되니 never 라는 타입이 들어가있다.

never 는 절대 있을 수 없는 값을 의미

그래서 이럴 땐 제네릭으로 꼭 타입을 명시적으로 해줘야 한다!

  const [names, setNames] = useState<string[]>([]);

 

✳️ useRef

  const formRef = useRef();

 

Ref 로 HTML DOM 요소를 가져와 쓴다면 그 노드 요소를 제네릭에 써주면 된다.

 

  const formRef = useRef<HTMLFormElement>();

 

그럼 아래에서 오류가 나는데..

 

 

초기값을 주지 않아서 undefined 가 될 수도 있다고 뜬다.

** 추론된 Ref 타입과 Ref 를 사용하는 곳의 타입이 다를 수 있다.

 

그러니 초기값을 null 로 넣어준다!

  const formRef = useRef<HTMLFormElement>(null);
 useEffect(() => {
    const form = formRef.current;
    if (form) form['username'].focus();
  }, []);

 

Ref 를 쓰는 곳을 보면 타입이 원하는대로 잘 추론되고 있다.