TypeScript | 기초 설정, 기본 데이터타입
기초 설정
기본 셋팅
1. npm 설치
해당 프로젝트에 npm init 해서 node.js 설치
2. lite server 의존성 설치 (optional)
npm install --save-dev lite-server
의존성 설정(package.json) 들어가서 "start" 명령어에 lite-server 등록하기
* 컴파일 하는 방법
TS 컴파일 명령어
tsc 파일명
// tsc app.ts
그럼 ts 파일이 컴파일되어 js 파일이 생성된다.
만약 IDE 단에서 오류를 발견했다고 하더라도 컴파일 자체를 막진 않는다. 따라서 컴파일 하기 전에 에러가 있는지 잘 확인하고 고친 후에 컴파일을 해야 한다. 안그러면 오류가 있는 버전의 JS 파일이 도출된다.
데이터타입
TS는 JS의 슈퍼셋. 즉 JS의 기존 데이터타입을 다 가지고 있다. 이에 더해서 TS 만이 제공하는 데이터타입들이 있다.
런타임이 아닌 개발 단계에서 타입이 결정된다.(dynamic types vs static types)
TS에는 타입 추론기능이 내장되어 있으므로 어느정도는 알아서 인식한다.
그러나 명시적으로 타입을 지정해주는 습관을 가져야 더 안전하고 DX 측면에서도 좋다.
1. 기본 데이터 타입 (Primitive Types)
- number: 숫자 타입
- string: 문자열 타입
- boolean: 불리언 타입
- null: null 타입
- undefined: undefined 타입
- symbol: 심볼 타입
- bigint: 큰 정수 타입
let num: number = 10;
let str: string = "Hello, TypeScript";
let bool: boolean = true;
let n: null = null;
let u: undefined = undefined;
let sym: symbol = Symbol("sym");
let big: bigint = 9007199254740991n;
2. 객체 타입 (Object Types)
- Object: 일반 객체 타입
- Array: 배열 타입
- Tuple: 튜플 타입
- Enum: 열거형 타입
- Function: 함수 타입
- Interface: 인터페이스
- Class: 클래스
// Object
let obj: {
name: string,
age: number
} = {
name: "John",
age: 25
};
// Array
let numbers: number[] = [1, 2, 3, 4];
let strings: Array<string> = ["one", "two", "three"];
// Tuple
let tuple: [string, number];
tuple = ["hello", 10];
// Enum
enum Color {
Red,
Green,
Blue
}
let c: Color = Color.Green;
// Function
let add: (x: number, y: number) => number;
add = function (x: number, y: number): number {
return x + y;
};
// Interface
interface User {
name: string;
age: number;
}
let user: User = { name: "Alice", age: 30 };
// Class
class Person {
constructor(public name: string, public age: number) {}
}
let person: Person = new Person("Bob", 40);
3. 제네릭 (Generics)
- 제네릭 타입은 다양한 타입을 허용하는 재사용 가능한 컴포넌트를 작성할 수 있게 합니다.
function identity<T>(arg: T): T {
return arg;
}
let output1 = identity<string>("myString");
let output2 = identity<number>(100);
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = (x, y) => x + y;
4. 고급 타입 (Advanced Types)
- Union: 여러 타입을 허용하는 타입
- Intersection: 여러 타입을 결합한 타입
- Type Aliases: 타입 별칭
- Literal Types: 리터럴 타입
- Mapped Types: 매핑된 타입
- Conditional Types: 조건부 타입
- Type Guards: 타입 보호
// Union
let union: number | string;
union = 10;
union = "hello";
// Intersection
type Person = { name: string };
type Employee = Person & { company: string };
let employee: Employee = { name: "John", company: "TechCorp" };
// Type Aliases
type ID = number | string;
let userId: ID;
userId = 123;
userId = "ABC123";
// Literal Types
let specificString: "hello" = "hello";
let specificNumber: 10 = 10;
// Mapped Types
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
interface Point {
x: number;
y: number;
}
let readonlyPoint: Readonly<Point> = { x: 10, y: 20 };
// Conditional Types
type NonNullable<T> = T extends null | undefined ? never : T;
type Result = NonNullable<string | number | undefined>; // string | number
// Type Guards
function isString(x: any): x is string {
return typeof x === "string";
}
function example(x: string | number) {
if (isString(x)) {
console.log(x.toUpperCase());
} else {
console.log(x.toFixed(2));
}
}
간단한 예시
1. 매개변수 타입 지정하기
const sum = (number1: number, number2: number) => {
return number1 + number2;
}
console.log(sum(4, 5));
2. input 태그로 두 숫자를 받아서 결과 보여주기 (HTML 코드는 생략)
// as ~~ 는 타입 지정
const number1Input = document.getElementById("number1") as HTMLInputElement;
const number2Input = document.getElementById("number2") as HTMLInputElement;
const submitButton = document.getElementById("submit") as HTMLButtonElement;
const resultDiv = document.getElementById("result") as HTMLDivElement;
submitButton.addEventListener("click", () => {
const number1 = parseFloat(number1Input.value);
const number2 = parseFloat(number2Input.value);
if (isNaN(number1) || isNaN(number2)) {
resultDiv.textContent = "숫자를 입력해 주세요.";
} else {
const sum = number1 + number2;
console.log(sum);
resultDiv.textContent = sum.toString();
}
})
Q. Enum 사용 vs Alias 사용
둘 다 타입들의 묶음이 필요할 때 사용하는데, 언제 enum을 쓰고 언제 alias를 사용할까?
보통, enum은 일반적으로 연관성이 있다고 받아들여지는 대상들에 대해서 사용한다. (ex: 접근권한(admin, user ..), Status(로딩, 성공, 에러) 등)
그 외적으로 프로젝트마다 생기는 특수한 필요성에 의해 타입 묶음이 필요한 경우에는 Alias를 사용한다.
쉽게 말하면, 복잡한 타입 선언이 필요한데, 자주 쓰일 것 같아서 별칭을 지어주고 싶을 때 Alias를 자주 사용한다.
enum 사용 예시 1 (요일)
enum Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
function getWeekdayName(day: Weekday): string {
switch (day) {
case Weekday.Monday:
return "Monday";
case Weekday.Tuesday:
return "Tuesday";
case Weekday.Wednesday:
return "Wednesday";
case Weekday.Thursday:
return "Thursday";
case Weekday.Friday:
return "Friday";
case Weekday.Saturday:
return "Saturday";
case Weekday.Sunday:
return "Sunday";
}
}
console.log(getWeekdayName(Weekday.Monday)); // "Monday"
enum 사용 예시2 (상태를 관리하는 객체)
enum Status {
Loading,
Success,
Error
}
interface ApiResponse {
status: Status;
data?: any;
error?: string;
}
function handleApiResponse(response: ApiResponse) {
switch (response.status) {
case Status.Loading:
console.log("Loading...");
break;
case Status.Success:
console.log("Data:", response.data);
break;
case Status.Error:
console.log("Error:", response.error);
break;
}
}
alias 사용예시 (타입 별칭)
type User = {
id: number;
name: string;
role: "admin" | "user" | "guest";
};
function printUserInfo(user: User) {
console.log(`ID: ${user.id}, Name: ${user.name}, Role: ${user.role}`);
}
const user: User = {
id: 1,
name: "John Doe",
role: "admin"
};
printUserInfo(user); // "ID: 1, Name: John Doe, Role: admin"