react Typescript
업데이트:
카테고리: react
/태그: Typescript
TypeScript
JavaScript 가 서버 측에서 사용하기가 힘들고 컴파일의 기능을 수용하지 못해서 Typescript가 대신하게 되었다.
JavaScript + 타입시스템
- JavaScript 코드를 더욱 단순화 하고 쉽게 디버그
- 개발자들이 버그 수정에 대한 고통을 줄여주기 위해서
데이터 미리넣어두기
md
파일을 이용해서 데이터를 미리 랜더할 수 있게 한다.- 원래는 서버에서 요청하여 데이터를 받지만 pre-render는 서버의 요청을 못보내니 미리 데이터를 넣어준다.
- 포스트를 클릭할 때 상세페이지를 보여주기 위해 임의로 데이터를 넣어준다.
posts
폴더를 생성하여md
파일로 데이터를 넣어준다.
md 파일에서 데이터 추출하기
상위 폴더에 lib
폴더 생성 및 post.ts
파일을 생성한다
설치 : npm install --save gray-matter
⇒ 데이터를 변경하는데 사용하는 모듈, md파일을 객체형태로
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
// path 미리 설정
const postsDirectory = path.join(process.cwd(), 'posts');
export function getSortedPostsData() {
// post 파일 이름 잡아주기
const fileNames = fs.readdirSync(postsDirectory);
// ['pre-rendering.md', 'ssg-ssr.md']
const allPostsData = fileNames.map(fileName => {
// md가 나오면 없애버린다
const id = fileName.replace(/\.md$/, "");
const fullPath = path.join(postsDirectory, fileName);
// 해당 파일을 불러들인다.
const fileContents = fs.readFileSync(fullPath, 'utf-8');
// 파일의 콘텐츠를 객체로 변환
const matterResult = matter(fileContents);
return {
id,
...(matterResult.data as {date: string; title:string})
}
})
// 정렬
return allPostsData.sort((a, b) => {
if (a.date < b.date) {
return 1
} else {
return -1
}
})
}
데이터 사용하기
import type { GetStaticProps, NextPage } from 'next'
import Head from 'next/head'
import { getSortedPostsData } from '../lib/posts'
import homeStyles from '../styles/Home.module.css'
// props로 데이터의 형식을 다 지정해준다.
const Home = ({ allPostsData }: {
allPostsData: {
date: string
title: string
id: string
}[]
}) => {
return (
<div className={homeStyles.container}>
<Head>
<title>Cheon Sohee</title>
</Head>
<section className={homeStyles.headingMd}>
<p>[Cheon Sohee Introdution]</p>
<p>
[This is a website]
</p>
</section>
<section className={`${homeStyles.headingMd} ${homeStyles.padding1px}`}>
<h2 className={homeStyles.hedingLg}>Blog</h2>
<ul className={homeStyles.list}>
// map으로 각각의 항목을 지정해준다.
{allPostsData.map(({ id, date, title }) => (
<li className={homeStyles.listItem} key={id}>
<a>{title}</a>
<br />
<small className={homeStyles.lightText}>
{date}
</small>
</li>
))}
</ul>
</section>
</div>
)
}
export default Home
// 위에서 작성했던 함수를 가져와 리턴값을 props로 넣어준다.
// const getStaticProps: GetStaticProps는 getStaticProps의 타입을 정해주는 것
export const getStaticProps: GetStaticProps = async () => {
const allPostsData = getSortedPostsData();
return {
props: {
allPostsData
}
}
}
TypeScript의 타입
"apple"
⇒ 문자열
⇒ value인데 문자열이 가지는 프로퍼티는, 메소드를 가지고 있는 value 이다.
Property : apple.length는 문자열의 속성인 길이를 제공, 문자열 자체에는 아무것도 하지 않음
Method : apple.lowerCase()는 문자열을 소문자로 반환, 문자열에 작업을 한 후 반환을 한다.
추가제공 타입
Any
- 잘 알지 못하는 타입을 표현해야 할 때 , 타입 검사를 통과하기 위해 사용한다.
- 최대한 사용하지 않는 것이 좋다.
nolmplictAny
를 사용하면 Any 타입에 오류가 발생한다.
Union
- 변수, 함수 매개변수에 대해 둘 이상의 데이터 유형을 사용할 수 있다.
let code: (string | number); code = 123; // OK code = "ABc" // OK code = false // Nope
Tuple
- 배열보다 특수한 형태로 사용한다.
- 지정된 형식에 다라 아이템 순서를 설정, 추가되는 아이템 또한 명시된 타입만 가능하다.
Enum
- 열거형을 의미
- 값들의 집합을 명명하고 이를 사용하도록한다.
- 기억하기 어려운 숫자대신 이름으로 명명하기 위해 사용된다.
- 선언 이후에는 변경할 수 없고, 속성값으로 문자열이나 숫자만 허용한다.
enum PrintMedia { Newspaper, Newsletter, Magazine, Book, } let mediaType: number = PrintMedia.Book // 3번째 집합을 불러온다. enum PrintMedia { Newspaper = 1, Newsletter = 2, Magazine = 40, Book = 23, } let mediaType: number = PrintMedia[40] // Magzine
void
- 데이터가 없는 경우 사용된다.
함수에 리턴이 없을 때
void를 지정할 수 있다.
Never
- 절대 발생하지 않을 값을 나타냄
- 함수의 리턴값으로 사용된다. 항상 오류를 리턴하거나 리턴값을 절대로 내보지 않는다.
- 무한루프를 돌릴때도 사용한다.
💡 void
와 Never
의 차이는?
void
: 유형이 값이기 때문에undefined
와null
을 가질 수 있다.Never
: 어떠한 값도 지정할 수 없다.
type annotation
개발자가 타입을 직접 말해 주는것
type inference
타입스크립트가 알아서 타입을 추론하는 것
annotation
꼭 해줘야 되는 경우
- any 타입을 리턴할 때
- json.parse의 경우 텍스트 데이터를 json 으로 파싱해준다. 개발자는 어떤 타입으로 리턴 될지 알고 있지만 타입스크립트는 전혀 모르기때문에 annotation을 해주어야 한다.
- 변수 선언을 먼저하고 나중에 초기화 할 때
- 선언을 먼저하면 타입스크립트가 추론할 수 없음
- 변수에 대입될 값이 일정치 못한 경우
- 여러타입이 지정될 때에는
| or statement
로 여러 타입을 애노테이션 해준다.
- 여러타입이 지정될 때에는
type assetion
추론한 타입을 우리가 원하는 대로 바꿀 수 있다. 이때 type assetion
이라는 매커니즘이 사용된다.
프로그래머가 타입에 대해 잘 알고 있을 때 사용한다.
as Foo
<Foo>
이 두가지 방식으로 사용하지만 <Foo>
는 react의 문법과 겹치므로 as Foo
를 사용한다.
file System 기반의 라우팅
리액트에서는 react-router를 사용하지만, Next.js에서는 파일이 페이지 디렉토리에 추가되면 자동으로 경로를 사용
할 수 있다.
Link
함수를 이용해서 페이지 이동을 구현한다.
// 어떤 파일로 이동할 것인지 링크를 걸어둔다.
<Link href={`/posts/${id}`}>
<a>{title}</a>
</Link>
설치: npm install remark remark-html --save
// 특정 하나의 데이터만 가져오기
export function getPostData(id: string) {
const fullPath = path.join(postsDirectory, `${id}.md`);
// 파일읽기
const fileContents = fs.readFileSync(fullPath, 'utf-8');
const matterResult = matter(fileContents);
// 데이터 변환작업
// md파일을 html 태그로 변환해준다.
const processedContent = await remark().use(remarkHtml).process(matterResult.content)
const contentHtml = processedContent.toString();
}
⇒ 변환작업을 거치고 나면 해당 형태로 데이터가 바뀌게 된다.
// 경로 가져오기
export const getStaticPaths: GetStaticPaths = async () => {
const paths = getAllPostIds();
// [{params: {id:...}}, {params: {id:...}}]
return {
paths,
// 데이터가 없으면 404 에러 발생
fallback: false
}
}
// 경로 기반으로 데이터 가져오기
export const getStaticProps: GetStaticProps = async ({params}) => {
// id
const postData = await getPostData(params.id as string)
return {
props: {
postData
}
}
}