리액트를 공부하기에 앞서, 자바스크립트의 확장언어인 타입스크립트 Typescript
가 무엇인지 공부해보았다.
먼저, 자바스크립트는 Unstrongly Typed Language
라서 변수를 선언할 때 자료형을 정해주지 않기 때문에 자료형이 다른 두 변수를 두고 연산을 했을 때 아무 오류도 띄우지 않는다는 문제점이 있다.
예를 들어, 자료형이 'number'인 1과 자료형이 'string'인 "1"을 더하는 연산을 했을 때, 오류가 발생하지 않고 11 이 출력된다.
이러한 문제를 해결하기 위해서 등장한 것이 바로 TypeScript.
타입스크립트는 Strongly Typed Language
라서 변수를 선언할 때 자료형을 미리 결정해준다는 차이점이 있다. 이러한 특징으로 인해 위에서 언급했던 문제점을 해결할 수 있다. 즉, 타입스크립트의 경우에는 자료형이 다른 두 변수 사이의 연산 자체에 대해서 오류를 띄워준다.
TS를 사용하면 코드의 양이 많아질 수는 있지만, 실시간으로 디버깅을 할 수 있다는 점이 매우 편리하다.
TypeScript Playground에서 코드를 입력하면서, 실제 JS로 번역이 어떻게 되는지 확인하면서 읽어보았다.
let student_id:number = 202303007;
let student_name:string = '이효원';
let is_at_school:boolean = true;
let student_id:any = 202303007; //명시적으로 any타입 지정
let student_id; //생략가능
any type을 사용하면 자료형을 지정해줄 수 있다는 타입스크립트의 장점을 누리지 못하기 때문에 사용을 지양.
이와 비슷한 타입으로는 unknown type이 있다.
let value:unknown = 123;
unknown type은 any type과 달리 어떤 타입인지 모르는 것이기 때문에 함부로 연산을 하지 않기 때문에 오류가 발생한다. 그래서 ts만의 장점을 살릴 수 있다.
두 개 이상의 타입을 허용할 때 사용.
let fact: string | number;
fact = 'Hello';
fact = 123;
fact = false; //error
let nums:number[] = [19, 65, 22];
let members:string[] = ['이효원', '이준하', '조훈히'];
let is_cor:boolean[] = [true, false, true];
let someArr:any[] = [0, 1, {}, 'str', [], false]; //any type
let selects:(number | string)[] = [102, 'apple']; //union type
자바스크립트에서는 지원하지 않는 데이터타입.
튜플은 크기와 타입이 고정된 배열array라고 이해하면 더 간단하다.
let user:[number, string, boolean];
user = [202303007, '이효원', true];
user = [10, true, '이효원', 20]; //오류(원소 개수, 타입이 맞아야 함)
열거형 데이터 타입.
타입의 값을 지정하지 않으면 타입 그 전 타입에 +1을 한 값을 자동으로 할당하고,
별도의 값이 지정되지 않으면 타입은 0부터 순서대로 값이 주어진다.
enum Team{
Manager = 101,
Planner = 208,
Developer = 302,
Designer //302 + 1 = 303 할당
}
let babo:number = Team.Manager; //(enum member) Team.Manager = 101
let mungtang:number = Team.Designer; //(enum member) Team.Designer = 303
//리턴 값 타입이 명시적으로 설정되지 않는 함수
function assignClass(name:string):void{
document.documentElement.classList.add(name);
}
//리턴 값 타입이 숫자인 함수
function factorial(n:number):number{
if(n < 0){return 0;}
if(n === 1){return 1;}
return n * factorial(n-1);
}
//리턴 값 타입이 문자인 경우
function repeat(text:string, count:number=1):string{
let result:string = '';
while(count--){result += text;}
return result;
}
TS에서의 인터페이스는 두 개의 시스템 사이에 상호 간에 정의한 약속 혹은 규칙을 포괄하여 의미한다.
즉, C++에서 배우는 Class클래스 처럼 타입의 '틀'로써 사용할 수 있는 것이 인터페이스이다.
(자바에서의 인터페이스와는 조금 다른 개념.)
//인터페이스 생성
interface Human {
name: string;
age: number;
talk(): void;
}
//인터페이스 자체를 타입으로 사용하여 객체 생성
const person: Human = {
name: "짱구",
age: 5,
talk: () => console.log("부리부리"),
};
//매개변수에서 인터페이스를 타입으로 받는다.
function booboo(a:Human):void {
console.log(`${a.name} is ${a.age} years old`);
};
booboo(person); //짱구 is 5 years old
person.boo(); //부리부리
제네릭은 자바에서 공부했던 것과 똑같다.
제네릭이란, 타입을 마치 함수의 파라미터처럼 사용하는 것을 의미한다.
function getText<T>(text: T): T{
return text;
}
getText<string>('hi');
getText<number>(10);
getText<boolean>(true);
여러가지 타입을 사용하고 싶을 때 any type을 사용할 수 있지만,
any를 사용하면 함수의 인자가 무슨 타입이며, 어떤 값이 반환되는지 알 수 없다.
function logText<T>(text: T[]): T[] {
console.log(text.length); // 제네릭 타입이 배열이기 때문에 `length`를 허용.
return text;
}
function logText<T>(text: Array<T>): Array<T> {
console.log(text.length);
return text;
}
function logText<T>(text: T): T {
return text;
}
// #1
let str: <T>(text: T) => T = logText;
// #2
let str: {<T>(text: T): T} = logText;
위 코드에서 #1과 #2는 같은 의미이다. 두가지 방법 모두 허용.
위 코드를 인터페이스를 사용해서 작성하면 아래와 같다.
interface GenericLogTextFn {
<T>(text: T): T;
}
function logText<T>(text: T): T {
return text;
}
let myString: GenericLogTextFn = logText;