본문 바로가기

Language/JavaScript(ES6)

타입 스크립트 시작하기(with Next)

여태까지 필요성을 크게 못 느껴서 사용은 커녕 뭐하는 건지도 몰랐는데, 사용 방법이 어렵지 않아서 이번 기회에 정리 하고 자주 사용해보려고 한다.

 

Typescript란

1
2
3
4
5
6
7
8
9
10
11
const areYouCool: boolean = true;
const answer: number = 42;
const typescript: string = "great";
const greetings: string = `
Hello, Readers!
Welcome to TypeScript.
`;
const hasType: Object = {
  TypeScript: true,
  JavaScript: false
};
 

위와 같이 변수:타입 과 같은 방식으로 변수에 타입을 지정해줄 수 있다.

이로써 기존의 인터프리터 방식에서 컴파일 방식으로 사용할 수 있게 되어 문법 체크나 자동 완성등에 도움을 받을 수 있다.

 

https://www.npmjs.com/package/@zeit/next-typescript

 

next에서 타입 스크립트를 사용하기 위해선 다음 주소를 따라가 패키지를 설치하고 설정을 해주어야 한다.

 

이후 실행했을 때 next 패키지가 무너지는 경우가 있는데 그럴 때는 재 설치 해주면 된다.

 

이외에 설치해주어야 하는게 있는데,

 

@types/next

@types/react

 

테스트 코드를 사용 중이라면

@types/jest 등등을 설치해주어야 한다. ( 사실 위의 패키지를 설치하고 제대로 설정했다면 이와 같은 패키지가 필요하다고 알려준다.)

 

설치가 되었다면 첫 컴포넌트를 만들어 보자!( 혹은 컴포넌트를 만들면서 나머지 패키지를 추가해보자!)

함수형 NextPage 컴포넌트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import * as React from "react"
import { NextPage } from "next"
 
const IndexPage: NextPage = () => {
  return (
    <div>
      <h1>Hello Next.js 👋</h1>
      <p>Wow!</p>
    </div>
  )
}
 
export default IndexPage
 
 

예제와는 다르게 처음부터 Type 위치에 NextPage라는 이상한 것이 위치한다.

NextPage는 다음과 같이 생겼다.

1
2
3
4
5
6
export type NextPage<= {}, IP = P> = {
  (props: P): JSX.Element | null
  defaultProps?: Partial<P>
  displayName?: string
  getInitialProps?(ctx: NextPageContext): Promise<IP>
}
 

type alias

타입 스크립트는 기본적으로 string, number, boolean과 같은 타입을 사용할 수 있다. 하지만 이 뿐만 아니라 사용자가 직접 타입을 만들어 줄 수도 있다. 이를 타입 별칭(type alias)라고 한다.

 

타입 별칭은 다음과 같이 작성한다.

type NewType = Type;

타입은 아래와 같이 어떤 타입도 올 수 있다.

type UUID = string;

type Height = number;

type AnotherUUID = UUID;

type Animals = Animal[];

type User = {

name: string;

height: number;

};

이처럼 Next의 Pages에 들어가는 컴포넌트의 타입을 NextPage가 해주고 있다는 정도만 이해하자.

함수형 NextNotPage 컴포넌트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import * as React from "react"
import Head from "next/head"
 
type Props = {
  title?: string
}
 
const Layout: React.FunctionComponent<Props> = ({
  children,
  title = "This is the default title"
}) => (
  <div>
    <Head>
      <title>{title}</title>
    </Head>
    <header>This is Header</header>
    {children}
    <footer>
      <hr />
      <span>I'm here to stay (Footer)</span>
    </footer>
  </div>
)
 
export default Layout

대표적인 NotPage 컴포넌트인 Layout을 만들어 보았다.

Page컴포넌트와 다르게 일반적인 컴포넌트는

React.FunctionComponent를 타입으로 가진다.

그리고 제네릭으로 Props를 주는데, Layout이 받는 Props를 뜻한다.

 

이 Props는 타입을 직접 만들어 넣어준다.

클래스 컴포넌트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import * as React from "react"
import { NextPageContext } from "next"
 
type Props = {
  item?: User //직접 만든 객체형 타입
  errors?: string 
}
 
class InitialPropsDetail extends React.Component<Props> {
  static getInitialProps = async ({ query }: NextPageContext) => {
    try { 
      const { id } = query
      const item = await findData(Array.isArray(id) ? id[0] : id) //직접 만든 메서드
      return { item }
    } catch (err) {
      return { errors: err.message }
    }
  }
 
  render() {
    const { item, errors } = this.props
 
    if (errors) {
      return (
        <Layout title={`Error | Next.js + TypeScript Example`}>
          <p>
            <span style={{ color: "red" }}>Error:</span> {errors}
          </p>
        </Layout>
      )
    }
 
    return (
      <Layout title={`${item ? item.name : "Detail"| Next.js + TypeScript Example`}>
        {item && <ListDetail item={item} />}
      </Layout>
    )
  }
}
 
export default InitialPropsDetail
 
 

클래스 컴포넌트는 Pages든 뭐든 React.Component를 상속 받는다.

 

주의해서 볼 장면은 getInitialProps에서 req에 받은 query의 타입을 NextPageContext 라는 타입으로 명명했다.

getInitialProps는 리액트 라이프사이클의 이른 시점에서 promise와 함께 사용하는 만큼 다음과 같은 타입으로 정해줘야 하는 것 같다.