React에 TypeScript 사용하기
학습 목표
- What & Why?
- TypeScript Basics
- Combining React & TypeScript
React + TypeScript: Adding Type Safety To React Apps
What & Why?
TypeScript는 JavaScript의 superset이다. 즉, JavaScript의 문법보다 더 확장된 프로그래밍 언어라는 뜻이다. TS는 정적 타입을 추가했다. JS는 동적 타입이기에 함수의 매개변수가 어떤 타입을 받을 지 정할 수 없다. 이는 버그를 만들기 때문에 TS를 이용해 정적 타입을 사용하면 버그를 줄일 수 있다. 참고로 함수의 매개변수 뿐만 아니라 여러 곳에서 타입을 지정할 수 있다.
TypeScript Basics
- 설치:
npm install typescript
TypeScript는 브라우저에서 사용할 수 없어서 JS로 컴파일 해줘야 한다. 타입 표기는 사라지겠지만 오류는 잡아준다.
- 컴파일러 실행:
npx tsc [파일명].ts
오류가 생겨도 일단 js 파일을 준다.
Types
- Primitives: number, string, boolean
- 타입은 소문자, 대문자는 JS 객체이다.
let age: number = 23; let userName: string; let isInstructor: boolean;
- 타입은 소문자, 대문자는 JS 객체이다.
- arrays, objects
- any 타입을 사용할 수 있지만 그럴거면 그냥,,, js를 쓰는게 나으니 사용을 비추한다.
let hobbies: string[]; // number[] // 객체를 생성하는 게 아니다. let person: { name: string; age: number; }; // object 배열 let people: { name: string; age: number; }[];
- any 타입을 사용할 수 있지만 그럴거면 그냥,,, js를 쓰는게 나으니 사용을 비추한다.
-
Function Types, parameters
// 반환값도 ts는 타입 추론하므로 필요한 경우 아니면 굳이 안해도 된다. function add(a: number, b: number): number | string { return a + b; } // 반환을 하지 않는 경우 void 타입을 사용한다. function printOutput(value: any) { console.log(value); }
-
Generics
- helper 함수 같은 것을 만들 때 유용하게 쓰이는 기능이다. 보통 상황에 따라 타입이 다르지만 input과 output의 type이 같은데 ts는 이해하지 못한다. 이럴 때 generics을 사용해 유연성과 타입 안정성을 높일 수 있다.
function insertAtBeginning(array: any[], value: any) { const newArray = [value, ...array]; return newArray; } const demoArray = [1, 2, 3]; const updatedArray = insertAtBeginning(demoArray, -1); // [-1, 1, 2, 3] const stringArray = insertAtBeginning(["a", "b", "c"], "d"); // 이렇게 사용하면 어떠한 정보도 얻을 수 없기에 오류가 발생하지 않는다. updatedArray[0].split("");
// array와 value는 같은 타입임을 알려줌. // T 대신 구체적인 type을 지정해줄 수 있다. Array<number> === number[] function insertAtBeginning<T>(array: T[], value: T) { const newArray = [value, ...array]; return newArray; } const demoArray = [1, 2, 3]; const updatedArray = insertAtBeginning(demoArray, -1); // [-1, 1, 2, 3] const stringArray = insertAtBeginning(["a", "b", "c"], "d"); // 이렇게 사용하면 첫번째는 number 타입으로, 두번째는 string 타입으로 추론되어 오류를 잡아낼 수 있다. updatedArray[0].split("");
-
type 추론 기능이 있어서 변수를 만들고 바로 초기화한 그 값의 자료형을 type으로 지정해서 재할당할 때 다른 자료형을 사용하면 오류가 생긴다. 이를 사용하면 명시적으로 타입을 지정할 필요가 없어서 편하다.
let age = 23; age = "23"; // error
-
유니온 타입이라는 기능도 제공하는데 이는 한 가지 이상의 타입을 지정하고 싶을 때 사용하면 된다.
let userName: string | string[] | number;
-
동일한 타입을 계속 지정해줄 일이 생긴다. 이는 귀찮으니 type aliases 기능을 사용할 수 있다. 관리하기 쉽다는 장점이 있다.
// not using type aliases let person: { name: string; age: number; }; let people: { name: string; age: number; }[]; // using type aliases type Person = { name: string; age: number; }; let person: Person; let people: Person[];
- TypeScript 공식 사이트
Combining React & TypeScript
-
새로운 React 프로젝트에 설치:
npx create-react-app [프로젝트 폴더명] --template typescript
파일 확장명이 .ts가 아닌 .tsx로 되어 있는데 그 이유는 jsx 문법을 사용하기 때문이다. 불필요한 경고창을 없애기 위함이다. 참고로 react가 알아서 자동으로 해주기 때문에 컴파일할 필요가 없다. package.json을 보면 @types로 시작하는 파일이 보이는데 이는 ts를 js로 번역해주는 번역기이다.
함수형 컴포넌트에 사용해보기
React.FC로 타입을 지정해줘야 하는데 이는 props.children을 기본으로 가진다. 뒤에 추가하고 싶은 속성을 Generics으로 추가해주면 된다.
const Component: React.FC<{ text: string }> = (props) => {
return <li>{props.text}</li>;
};
모델 데이터를 사용하여 타입을 명시해줄 수 있다.
// models/Todo.ts
class Todo {
id: string;
text: string;
constructor(todoText: string) {
this.text = todoText;
this.id = new Date().toISOString();
}
}
// Todos.tsx
const Todos: React.FC<{ items: Todo[] }> = (props) => {
return (
<ul>
{props.items.map((item) => (
<TodoItem key={item.id} text={item.text} />
))}
</ul>
);
};
- props.children 오류 발생
- React18이상에서는 children을 기본으로 가지지 않는다고 한다. 그래서 타입을 명시해줘야 한다.
React.FC<React.PropsWithChildren>
- React18이상에서는 children을 기본으로 가지지 않는다고 한다. 그래서 타입을 명시해줘야 한다.
useState, useRef에 사용해보기
// 만약 타입을 명시해주지 않으면 초깃값에서 추론된 타입밖에 못 쓴다.
const [todos, setTodos] = useState<Todo[]>([]);
// 참조하는 DOM의 타입을 지정하면 된다.
const todoTextInputRef = useRef<HTMLInputElement>(null);
// event도 타입 지정해줘야 한다. ts는 모른다.
const submitHandler = (event: React.FormEvent) => {
event.preventDefault();
// 확실히 값을 들고 온다면 !.로 사용해주면 된다. null일 수도 있다면 ?.로 들고 온다.
const enteredText = todoTextInputRef.current!.value;
};
Context API에 사용해보기
// createContext에 명시해줘야 한다.
export const TodosContext = createContext<TodosContextObj>({
items: [],
addTodo: (todoText: string) => {},
removeTodo: (todoId: string) => {},
});
// provider도 컴포넌트이기 때문에 React.FC로 명시, props.children을 위해 타입 명시
const TodosContextProvider: React.FC<React.PropsWithChildren> = (props) => {};
// 사용은 기존과 똑같이 해주면 된다.
tsconfig.json은 컴파일하는데 필요한 루트 파일과 옵션을 지정한다. 자세한 건 아래 참조사이트에서 확인해보자. 중요한 것만 주석을 달아놨다.
{
"compilerOptions": {
"target": "es5", // js 버전에 따라 변경한다. ex) ex5이하인 경우, arrow func을 function 표현식으로 변환
"lib": ["dom", "dom.iterable", "esnext"], // 타입 라이브러리
"allowJs": true, // js 파일 허용 여부, ts 파일에 js 파일도 같이 사용할 수 있다.
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true, // 엄격함! true면 타입을 꼭 명시할 수 있도록 타입 추론인 경우 제외하고 에러가 생긴다.
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx" // JSX 구문 내보내는 방법 제어
},
"include": ["src"]
}
수강 완료!
강의명
- Udemy : React 완벽 가이드
댓글남기기