React에 TypeScript를 함께 쓰고 있지만 지식의 얕음을 느끼고 다시 공부했다.
도구를 그냥 쓰는 것과 잘 알고 쓰는 것은 역시 다름을 느낀다.
0. React + TypeScript
✍ What? Why?
타입스크립트는 자바스크립트의 superset
자바스크립트의 기본적인 문법, 코드 작성법 등을 그대로 사용하지만 새로운 기능이 추가됨
- 타입스크립트는 자바스크립트의 라이브러리가 아니기 때문에 js기능을 확장하지는 않는다.
- 하지만 확장된 문법을 가지고
- 정적 타입을 갖는다.
JS : dynamically tpyped (동적 타입 언어)
TS : JS + static typing (정적 타입 언어)
✅ JS
함수 선언 시점에는 자료형을 특정 짓지 않는다
매개 변수를 받는다는 것만 알고 있음.
사용한 타입을 정해두지 않은 삳태에서 변수를 받아 사용하는 것.
✅ TS
매개변수 뒤에 콜론 : 을 추가하고 타입 표기function add(a:number, b:number){}
이건 두 숫자가 숫자형이여야 한다는 것을 드러냄.
이를 통해 의도치 않은 함수 사용을 잡아낼 수 있다. => 오류를 피할 수 있다(코드를 작성할 때 바로 오류 표시)
✨ 중요
브라우저에서 TS코드를 실행할 수는 없다.
따라서 TS를 JS형태로 컴파일해야 한다. 이 때 타입 표기는 삭제된다.
하지만 컴파일 단계에서 오류를 표시해준다. 런타임 전 컴파일 단계에서 오류를 찾아낼 수 있다는 장점이 있음
1. TypeScript Basics
Primitives : number, string, boolean
More complex types : arrays, objects
Function types, parameters
📌 Primitives
한 변수를 만들어 숫자를 저장한다면 변수 let age: number = 25;
처럼 할당할 수 있다.
let userName : string;
let isInstructor : boolean = true;
null으로 저장하는 경우는 드물다.
null과 undefined는 다른 방식으로 사용된다
📌 Arrays, Objects
✅ 문자열 배열
let hobbies: string[]
이 배열에 다른 자료형을 넣으면 오류가 생긴다
타입으로도 지정할 수 있음
✅ 객체 저장하기
let person;
person = {
name: 'A',
age: 12.
};
기본 타입은 any로 간주됨.
이렇게 any로 간주하면 어떤 타입이든 저장될 수 있음. 하지만 사용하지 않는게 좋다.
타입스크립트의 사용 목적과 반대되기 때문에 any 대신 명확하게 저장할 객체를 지정해주는 것이 좋다.
✅ 배열 안에 객체를 넣을 수도 있다
let people: {
name: string;
age: number;
}[];
📌 타입 추론
let course = 'React'
course = 123;
에서 타입을 추가하지 않았는데도 오류가 생긴다.
타입스크립트는 명시적인 타입 표기가 없어도 타입을 알아내려고 한다.
✨ 작동방식
변수를 만들고 초기화하면 타입스크립트는 할당된 값의 자료형을 보게 된다
그리고 변수에 저장된 값의 Type를 알아낸다
해당 값의 자료형을 이 변수의 타입으로 여기고 사용한다
=> 다른 타입의 값을 사용하면 오류가 생긴다
이렇게 타입 추론을 이용해서 작성하면 불필요하게 타입을 지정하지 않아도 되서 효율적이다
가능하면 타입 추론을 사용하는 것을 추천.
📌 유니온 유형 사용하기
다양한 타입을 여러 개 저장하는 경우가 있다.
한 개 이상의 타입을 지정할 수 있게 해주는 기능 : 유니온 타입
정의할 때 한 개 이상의 타입을 사용할 수 있다.
let cours: string | number = 'Hello'
값과 타입을 좀 더 유연하게 정의할 수 있음
📌 Type Aliases (타입 별칭)
동일한 타입을 정의하는 것은 비효율적이다.(코드 중복)
기본(Base)타입을 만들고 그 타입 별칭을 만드는 것
type Person = {
name:string;
age:number;
};
그리고 Person을 써야 하는 곳에let people: Person[];
이런식으로 사용해주면 된다
코드가 간결해지고 관리도 쉬워진다
📌 함수 및 함수 유형
1. Type을 가진 함수
함수를 사용할 때 타입을 지정하는 위치가 따로 있다function add(a: number, b: number){
return a+b;
}
이런 함수에서도 타입 추론이 사용된다.
이 함수에서 값을 반환하고 TS는 반환 값의 타입을 알게 된다.
마우스를 올리면function add(a: number, b: number) : number
을 확인할 수 있다. 마지막 number은 타입 추론으로 나온 값으로, 타입스크립트가 추론한 것.
반환되는 것이 숫자임을 알고 타입 추론을 했다.
명시적으로 지정할 수도 있음.
function printOutput(value : any){
console.log(value);
}
이런 코드가 있다면, 이 값에 명확한 타입을 지정할 필요는 없다.
하지만 이 함수는 아무것도 반환하지 않는다.
이 때 사용하는 반환 타입이
✨ void 타입.
null과 undefined와 비슷.
함수에 반환 값이 없다는 것을 뜯한다function printOutput() : void
만약 함수의 반환 값을 받아와야 한다면 undefined 타입으로 값을 받아야 한다.
void는 함수의 반환 타입에만 사용된다.
2. generic (제네릭 타입)
function insertAtBeginning(array:any[], value: any){
const newArray = [value, ...array];
return newArray;
}
이 함수의 장점은 기존 배열을 변경하지 않고 아예 새로운 배열을 얻을 수 있다는 점.
여기에const demoArray = [1,2,3];
const updatedArray = insertAtBeginning(demoArray,-1);
문제는 추론된 배열의 타입이any라는 것(insertAtBeginning에서)
타입을 any로 지정했기 때문에 타입스크립트는 array에 숫자로만 구성된 배열이 들어온다는 것을 모른다.
- any를 이용하지 않으면 문자열 배열이 들어왔을 때 사용할 수 없고
- any를 이용하면 TS로부터 어떤 지원도 받을 수가 없다.
=> 우리가 필요해서 정의한 any[]
타입 때문에 TS는 어떤 것도 알지 못한다
이 때 '제네릭'을 사용하면 된다
함수를 제네릭 함수로 변환할 수 있다.
함수 이름과 매개변수 목록 사이에 <>
추가
function insertAtBeginning<T>(array: T[], value: T){
const newArray = [value, ...array];
return newArray;
}
이 제네릭 타입을 통해 TS에게 any 타입이 아니라는 것을 알려줌
하지만 array와 value가 같은 type을 가져야 한다는 것을 알려줌
=> 함수에 타입 안정성과 유연성을 준다
어떤 타입이든 사용할 수 있지만 한 입을 사용하면 제네릭을 통해 해당 타입으로 고정되어 동작한다.
2. Combining React & TypeScript
props에 type를 설정해둬야 한다.
함수의 props가 어떤 타입인지를 받아와야 함
function Todos(props: { string[] }){
}
이런식으로
하지만 이게 틀릴 수도 있다.
props는 키-값 쌍도 가지고 있을 수 있지만 children 타입도 올 수 있는데 이런 대비가 어렵다.
📌 따라서 제네릭 타입을 사용
우리가 만든 함수형 컴포넌트에서 몇 가지 설정을 추가하여 React 함수형 컴포넌트로 동작하게 만들어 children같은 기본 props를 사용할 수 있게 한 다음에 다른 객체도 추가 가능하게 만들 수 있다.
const Todos: React.FC = (props) =>{
}
dl React.FC는 리액트 패키지에 정의된 타입이다.
React 패키지에 내장된 타입 정의.
이 정의를 사용함으로써 이 함수가 함수형 컴포넌트로 동작한다는 것을 명확히 하는 것.
이제 우리가 새로 정의한 것들을 props 객체에 합칠 수 있다.
const Todos: React.FC<{items: string[]}> = (props) =>{
}
여기서 React.FC는 이미 제네릭 타입.
내부적으로 사용되는 제네릭 타입에 구체적인 타입을 집어넣는다.
이렇게 하는 이유는 TS로 하여금 값을 추론하게 할 수 없기 때문.
함수를 정의하고 TS에게 내부적으로 어떻게 처리해야 하는지 알려주고 싶기 때문에 추론하지 못하게 한다.
여기서 알수 있는 제네릭 타입의 다른 점
'FC'라는 제네릭 타입의 용도에 맞게 쓸 하나의 타입을 명시적으로 설정하는 것,
이 FC타입은 제네릭 값이고, 여기에 집어넣을 새로운 타입은 우리가 만들 props 객체. (함수형 컴포넌트에 맞게 props를 정의한 객체)
이게 제네릭인 이유는 함수형 컴포넌트마다 props에 대한 정의가 다르기 때문
=> React와 TS를 사용해 제네릭 타입을 사용하는 또 다른 방법
간단하게 FC는 객체의 기본 타입인 children 프로퍼티와 새로 들어오는 type들을 합쳐주는 기능을 한다고 보면 된다.
+
FC로 key같은 것도 추가할 수 있음.
key = {item.id}를 props로 받아와서 새로운 component에 따로 key를 표시하지 않아도 알아서 그려준다.
📌 React.FormEvent
React 패키지가 제공하는 타입 중에 event 타입도 있다.
event가 발생했을 때 사용되는 타입.
const submitHandler = (event : React.FormEvent) =>{
};
폼 제출 이벤트의 경우 FormEvent 타입
onClick 이벤트 리스너의 경우 MouseEvent 타입
📌 Refs
타입스크립트로 작업할 때는 우리가 만든 레퍼런스에 타입을 추가시켜줘야 한다
명확하게 이 HTML 요소에 맞는 레퍼런스가 아니기 때문에 TS에서는 오류가 발생하게 된다.
=> 따라서 이 ref에 저장될 데이타가 어떤 타입인지 명확히 밝혀야 한다.
=> 제네릭 타입 사용.
useRef 자체가 제네릭 타입으로 정의되어 있다.
const todoTextInputRef = useRef<HTMLInputElement>(null);
- 어떤 값을 저장할 것인지
- 어떤 HTML 요소를 저장할 것인지
를 설정해야 한다.
어떤 값을 저장?
시작 값을 넣어줘야 한다. 보통 시작 값은 null로 시작된다.
어떤 HTML 요소를 저장?
여기서는 HTMLInputElement를 이용.
모든 돔(DOM) 요소들은 미리 정의된 타입을 가진다.(TS에서 해당 요소를 참조할 때 이용할 수 있다.)
📌 ? !
?
값이 있을 때만 값을 가져온다 (null이 있을 수 있을 상황 가정)
!
이 시점에는 절대 null이 아니다! - 100% 확신할때만 사용해야 한다.
'✍ 공부 > React' 카테고리의 다른 글
[ 🐱💻 강의 노트 ] React 완벽 가이드 강의 정리 섹션 10 | 리듀서(Reducer)을 사용하여 부작용 처리 & 컨텍스트 API(Context) 사용하기 (0) | 2022.06.12 |
---|---|
React 프로젝트 구조 잡기 (0) | 2022.06.08 |
[ 🐱💻 강의 노트 ] React 완벽 가이드 강의 정리 섹션 29 | 리엑트 요약 및 핵심 기능 (0) | 2022.05.31 |
[ 🐱💻 강의 노트 ] React 완벽 가이드 강의 정리 (0) | 2022.05.26 |
React에서 상태관리하기 (자체적 방법과 라이브러리 비교하기 Recoil, Redux) (0) | 2022.04.21 |