[TS] 리액트에서 타입스크립트 사용하기

Suyeon·2020년 11월 22일
8

Typescript

목록 보기
12/12

Setup

Create-react-app 기준으로, 밑의 방법으로 타입스크립트를 설치한다.

1️⃣ 새로운 프로젝트

  • npm init react-app my-app --template typescript

2️⃣ 기존의프로젝트에 추가하려는 경우

  • npm i --save typescript @types/node @types/react @types/react-dom @types/jest
  • tsc --init tsconfing.json 파일 생성

Syntax

밑의 예시들은 Functional Component 기준으로 작성되었다.

1️⃣ Arrow function

// (1) React.Fc
const Greetings: React.FC<GreetingsProps> = ({ name, mark }) => (
  <div>
    Hello, {name} {mark}
  </div>
);

// (2) Without React.FC
const Greetings = ({ name, mark }: GreetingsProps) => (
  <div>
    Hello, {name} {mark}
  </div>
);

2️⃣ Function keyword

function Greetings({ name, mark }: GreetingsProps) {
  return (
    <div>
      Hello, {name} {mark}
    </div>
  );
}

useState

// (1) value or null
const [info, setInformation] = useState<Information | null>(null);

// (2) object or array
type Todo = { id: number; text: string; done: boolean };
const [todos, setTodos] = useState<Todo[]>([]);

// (3) You don't need this
 const [count, setCount] = useState<number>(0);

useRef

// (1) DOM
const inputRef = useRef<HTMLInputElement>(null);
return <input type="text" id="todo-text" ref={inputRef} />
  
// (2) 
const id = useRef<number>(0);

Libraries

사용하려는 자바스크립트 라이브러리가 타입스크립트를 지원한다면, 라이브러리 이름 앞에 @types를 붙여서 설치하면 된다. (예시: npm i @/typesreact-router-dom)

Styled-components 사용하기

  • npm i styled-componens @types/styled-commponents

Prop의 Type 설정하기

// 1️⃣ type or interface
type BtnWrapperProps = {
   correct: boolean;
};

export const BtnWrapper = styled.div<BtnWrapperProps>`
    background: ${({ correct }) => correct ? 'green' : 'red' };
`;

// 2️⃣ generic
export const BtnWrapper = styled('div')<{ correct: boolean }>`
    background: ${({ correct }) => correct ? 'green' : 'red' };
`;

// 3️⃣ css
/* cssprop.d.ts 파일생성후, 
import * as types from 'styled-components/cssprop';
*/

import styled, { css } from 'styled-components';

const ColorPaletteContainer = styled('div')<{ isInputField?: string }>`
  max-width: 128px;

  ${({ isInputField }) =>
    isInputField &&
    css`
      bottom: 80px;
    `}
`;

(참고)
css 안에서 ${props => props.isPinned ? 'black' : 'white'}와 같이 조건적으로 스타일을 적용할 경우 에러가 났는데 이 때 props에 타입을 설정해주니 해결되었다.


Custom Html Attribute

리액트를 사용하다보면 custom props를 자주 사용하게 된다. Custom Html Attr(props)을 사용하는 방법을 알아보자

index.d.ts

src/types/index.d.ts 파일을 생성하고 사용할 props를 정의해준 다음, 평소와 같이 사용하면 된다.

d.ts 파일은 모듈에 대한 타입스크립트 타입 정보를 제공하는 파일이다. 예를 들어, 이미지를 import 하고 싶을 때, image.d.ts파일을 생성하고 declare module '*.jpg';와 같이 정의하면 된다.

// index.d.ts
import 'react';

declare module 'react' {
  export interface HTMLAttributes<T> {
    path?: any; // Custom props 
  }
}

컴포넌트에서 사용하기

// Content.js
  return (
    <Wrapper>
      <Content path={path === 'keep' ? path : null} />
    </Wrapper>
  );

(참고)
index.d.ts에서 props를 정의하고 나면 계속 module has no exported member react라는 에러가 났는데 props의 타입이 틀려서 그랬던 것 같다. path={path === 'keep' ? path : null}의 경우 일단 any로 바꾸었더니 정상적으로 작동했다.


react-router-dom

withRouter

RouteComponentProps을 import해서 타입으로 지정해준다.

import { withRouter, RouteComponentProps } from 'react-router-dom'; // (*)

const Logo = ({ location }: RouteComponentProps) => { // (*)
  return <Content />
};

export default withRouter(Logo);

match 속성을 사용한다면, 아래와 같이 사용하면 된다.

import { RouteComponentProps } from 'react-router-dom';

interface MatchParams {
  id: string; // params
}

const LabelPage = ({ match }: RouteComponentProps<MatchParams>) => {
   const { labelName } = match.params;
 // ... 
}

useSelector

// store/reducer/index.tsx
const rootReducer = combineReducers({
  view,
  notes,
});

export default rootReducer;
export type RootState = ReturnType<typeof rootReducer>; // (*)

// Using it 
import { RootState } from 'store/reducers/index';
const labels = useSelector((state: RootState) => state.notes.labels);

setState

setStateprops로 자식 컴포넌트에게 전달할 경우

// Parent.tsx
interface Note {
  title: string;
  content: string;
};

const Parent = () => {
   const [note, setNote] = useState<Note>({ title: '', content: '' });
  
   return <Child setNote={setNote} />
}

// Child.tsx
import React, { Dispatch, SetStateAction } from 'react'; // (*)
import Note from 'components/Parent/Parent';

interface ChildProp {
   setNote: Dispatch<SetStateAction<Note>> // (*)
}

useState를 자주 자식 컴포넌트에게 넘겨줄 경우, type Dispatcher<S> = Dispatch<SetStateAction<S>>와 같이 type alias를 작성할 수 있다.

event

profile
Hello World.

0개의 댓글