각각의 component와 pages마다 type을 선언할 때 마다, type이나 interface를 재선언해주는 것이 효율적이지않은 것 같다고 느낀 찰나에, 다른 한 파일에 타입을 지정해놓고 필요할때 마다 꺼내서 사용하면 좋을 것 같았다.
살펴보니 NextJS 프레임 워크에서 구현이 되어 있었는데 next-env.d.ts 가 있었고,
nextjs 프로젝트를 생성 했을때, 위의 파일이 자동적으로 생성된다.
🌳
next-env.d.ts🌳
- nextjs 공식문서에서도 타입과 인터페이스를 관리하는 파일로 해석한다.
- 해당 파일에 타입을 지정 했을 시, 자동으로 import없이 타입들을 사용 가능하다는 것이 큰 장점이다.
- api url같은 상수 값도 여기에 type지정이 가능하다.
// next-env.d.ts
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// 예시: 전역적으로 사용될 사용자 정의 타입
interface CustomType {
id: string;
name: string;
}
type PropsCustomButton = {
title:string;
handleClick?: MouseEventHandler<HTMLButtonElement>;
btnType?: "button" | "submit";
textStyles?: string;
rightIcon?: string;
isDisabled?: boolean;
className?: string;
}
// 예시: 프로젝트 전체에서 사용될 상수
declare const API_BASE_URL: string;
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
이런식으로, CustomButton 컴포넌트가 필수로 받는 props 선택적으로 받을 수 있는 props의 타입을 모두 정의하면된다.
type PropsCustomButton = {
// 필수 props
title: string; // 버튼에 표시할 텍스트, 필수
btnType?: "button" | "submit"; // 버튼 타입, 기본값이 "button"
// 선택적 props
handleClick?: MouseEventHandler<HTMLButtonElement>; // 클릭 이벤트 핸들러, 선택적
textStyles?: string; // 텍스트 스타일, 선택적
rightIcon?: string; // 아이콘, 선택적
isDisabled?: boolean; // 버튼 비활성화 여부, 선택적
className?: string; // 추가적인 클래스명, 선택적
}
🌳선택적 props (?):🌳
타입 정의에서 선택적으로 받을 수 있는 값을 나타내는 타입스크립트 기법.
타입스크립트에서 props를 정의할 때, 선택적 값은 ?를 사용하여 정의된다.
type Props = {
title: string; // 필수
handleClick?: () => void; // 선택적
};
여기서 handleClick?: () => void;와 같이 정의된 handleClick은 선택적이다.
즉, 해당 prop을 전달하지 않아도 된다.
참고로! 무조건 선언해줘야 하는 부분이 있다.
tsconfig.json에 반드시 include해줘야하는데 해당 파일 내부 속 include 배열 안에 "next-env.d.ts"를 반드시 추가해줘야 한다.
이 구분은 기본적으로 빌드시에 자동생성되어 있지만 없다면 추가해주자!
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
작업 중 "next-env.d.ts"에 선언해놓은 타입들이 깃에 반영되지않고, 내용들이 사라져서 살펴보니 우선 .gitignore에 포함되어있었고 그렇다면 왜 기본으로 .gitignore에 들어가있을까를 생각해보며 내용을 좀 더 살펴봤다.
공식문서 왈 :
커스텀 타입을 선언해야 할 때, next-env.d.ts를 수정하고 싶을 수 있습니다. 그러나 이 파일은 자동으로 생성되므로 변경 사항이 덮어쓰여질 것입니다. 대신 새 파일을 생성하고 new-types.d.ts라고 이름을 짓고 이를 tsconfig.json에 참조하세요:
{
"compilerOptions": {
"skipLibCheck": true
//...생략...
},
"include": [
"new-types.d.ts",
"next-env.d.ts",
".next/types/**/*.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": ["node_modules"]
}
next-env.d.ts 파일이 있는 위치와 동일한 위치에 new-types.d.ts 파일을 생성하고, 해당 파일 내에 타입을 선언해주면된다!
//new-types.d.ts
type PropsCustomButton = {
title: string;
handleClick?: MouseEventHandler<HTMLButtonElement>;
btnType?: "button" | "submit";
textStyles?: string;
rightIcon?: string;
isDisabled?: boolean;
className?: string;
};
export default PropsCustomButton; //반드시 export를 해주어야함.
그리고 CustomButton.tsx에서 사용하기.
"use client";
import PropsCustomButton from "../../../new-types"; //이와 같이 import 시킨다.
import Image from "next/image";
import "./CustomButton.scss";
const CustomButton = ({
title,
handleClick,
btnType = "button",
textStyles,
rightIcon,
isDisabled = false,
className = "",
}: PropsCustomButton) => {
return (
<button
className={`listBtn ${className}`} // className은 추가될 수 있도록 설정
type={btnType}
disabled={isDisabled}
onClick={handleClick}>
<span className={`flex-1 ${textStyles}`}>{title}</span>
{rightIcon && (
<div>
<Image src={rightIcon} alt="icon" fill className="object-contain" />
</div>
)}
</button>
);
};
export default CustomButton;
그리고 실제 위 버튼 공통 컴포넌트를 사용할 때에
<CustomButton btnType="button" title="타이틀영역" className="buttonCommon" />
이런식으로 타입에 맞게 작성해주면 되는데, 예를들어 title에서 string이 아닌 number를 작성하면 오류가 난다.!!
타입 선언
프로젝트에서 사용하는 외부 라이브러리나 모듈의 타입을 선언함으로써 TypeScript가 해당 모듈의 타입을 인식하고 사용할 수 있다.
환경 설정
환경 변수의 타입 선언이나 모듈의 경로 설정 등을 포함한 Next.js 프로젝트의 환경 설정과 관련된 TypeScript 타입을 정의할 수 있다.
커스텀 타입
프로젝트 내에서 공유되는 커스텀 타입을 정의할 수 있다. 프로젝트 전체에서 일관된 타입을 유지하고 재사용하기 용이해진다.
공식문서 https://nextjs-ko.org/docs/pages/building-your-application/configuring/typescript