[멋사] TypeScript & React 기초 (1)

·2023년 11월 7일
0

likelion

목록 보기
14/14

TypeScript?

자바스크립트에 타입을 부여한 언어

자바스크립트의 모든 기능을 포함하면서 정적 타입을 지원한다. (자바스크립트는 동적 타입)
자바스크립트 기능들을 제공하면서, 그 위에 자체 레이어를 추가 -> 즉, 자바스크립트의 확장된 언어이다.

타입스크립트는 본래 자바스크립트가 구현할 수 없었떤 타입체킹과 같은 기능을 구현하고, 컴파일러를 통해 JS로 변환한다.

타입스크립트의 기능

1. 에러의 사전 방지

function sum(a: number, b: number) {
  return a + b;
}
sum(10, 20); // 30
sum('10', '20') // 1020
				// Error: '10'은 number에 할당될 수 없습니다.

2. 코드 가이드 및 자동완성

자동완성 및 추천, 디버깅 등 유용한 기능들을 제공하기 때문에 생산성이 증가한다.

function sum(a: number, b: number) {
  return a + b;
}
const result = sum(10, 20);
result.toLocaleString(); // 특정 언어의 표현 방식에 맞게 숫자를 표기하는 메서드

result 라는 변수의 타입이 코드를 작성하는 시점에 number라는 것을 JS는 인지하지 못하나, TS를 사용할 경우 result에 대한 타입이 지정되어 있기 때문에 편집기에서 해당 타입에 대한 메서드를 미리보기로 띄워줄 수 있다.

타입스크립트의 타입

Primitive Types (원시 타입)

  • boolean: 참 또는 거짓을 나타내는 논리 데이터 타입
  • number: 모든 숫자를 나타내는 데이터 타입
  • string: 문자열을 나타내는 데이터 타입
  • null: null 자체인 특수한 데이터 타입 (명시적 없음)
  • undefined: undefined 자체인 특수한 데이터 타입 (암시적 없음)
  • symbol: ES6에서 도입된, 변경 불가능하고 고유한 값인 심볼을 나타내는 데이터 타입
  • bigint: 큰 정수를 표현할 수 있는 새로운 데이터 타입 (Es2020에 도입)

Basic Types

  • object: 객체를 나타내는 데이터 타입
  • array: 배열을 나타내는 데이터 타입 (variable-length)
  • tuple: 배열의 길이가 고정되고 각 요소의 타입을 지정할 수 있는 배열 형식(fixed-length)
  • enum: 특정 값(상수)들의 집합
  • any: 모든 타입에 대해서 허용
  • void: 반환 값이 없는 함수의 반환 타입
  • never: 함수의 끝에 절대 도달하지 않는다는 의미를 지닌 타입
// 타입 표기 예시 
let str: string = 'hi'; // string
let num: number = 10; // number
let isLoggedIn: boolean = false; // boolean
let arr: number[] = [1, 2, 3]; // array
let arr: Array<number> = [1, 2, 3]; // array-generic
let arr: [string, number] = ['hi', 10]; // tuple
let arr: any = ['a', 2, true]; // any

// 변수를 선언할 때 꼭! 항상! 타입을 써야하는 건 아니나,
// 자동으로 추론된 타입에 대해서도 fixed type이 됨

function printSomething(): void {
  console.log('sth');
} // void

function neverEnd(): never {
  while (true) {
    
  }
} // never

function greet(name: string) {
  console.log("Hello, " + name.toUpperCase() + "!!");
} // 매개변수 타입 표기

any unknown never ?

any는 모든 종류의 값에 사용될 수 있지만, 해당 변수에 대한 타입 검사를 완전히 무시하게 되므로 실수를 컴파일단계가 아닌 런타임에서만 발견할 수 있게 되어 TS의 의미가 퇴색된다.
-> 따라서 가능한 any 대신 명확한 타입을 지정해야 하며, 변수가 어떤 타입을 가질지 예측할 수 없거나 알 필요가 없는 경우에나 제한적으로 사용해야 한다.

Union Type

| 연산자를 사용하여 타입을 여러 개 연결하는 방식

function printId(id: number | string) {
  console.log("Your ID is: " + id);
} 
printId(101); // OK
printId("202"); // OK
print({ myID: 22342 }); // Error

인터페이스와 타입별칭(Interface & TypeAlias)

Interface (인터페이스)

상호 간에 정의한 약속 혹은 규칙을 말한다.
타입스크립트에서는 객체 타입을 단순 Object로 선언할 수 없으므로, interface를 통해 key, value까지 타입을 선언한다.

// 인터페이스명은 PascalCase 사용
interface Human {
  name: string; // name 키는 문자열 타입
  age: number; // age 키는 number 타입
  boo(): void; // boo 함수는 void 타입
}

// 인터페이스 자체를 타입으로 주어서 객체 생성
const person: Human = {
  name: "da",
  age: 5,
  boo: () => console.log("this is boo!"),
};

// 매개변수에서 인터페이스를 타입으로 받기
function booboo(a: Human): void {
  console.log(`${a.name} is ${a.age} years old!`}
};

booboo(person); // da is 5 years old
person.boo(); // this is boo!

Optional Property

객체 타입은 일부 또는 모든 프로퍼티의 타입을 선택적인 타입, 즉 optional로 지정이 가능 -> 프로퍼티 이름 뒤에 ? 표기

interface CraftBeer {
  name: string;
  hop?: number;
}

let myBeer = { // :CraftBeer 가 빠졌나?
  name: 'Saporo'
};

function brewBeer(beer: CraftBeer) {
  console.log(beer.name); // Saporo
}

brewBeer(myBeer);

Readonly

읽기전용속성(Readonly Property)는 인터페이스로 처음 생성할 때만 값을 할당하고, 그 이후에는 변경할 수 없다.
인터페이스로 객체를 처음 선언하여 값을 대입한 이후, 따로 프로퍼티에 접근해서 수정하려고 하면 오류가 발생한다.

interface User {
  name: string;
  age: number;
  gender?: string;
  readonly birthYear: number; // 읽기 전용 속성
}

let user: User = {
  name: 'jeff',
  age: 30,
  birthYear: 2010, // 최초에 값을 초기화 할 때만 할당 가능
};

user.birthYear = 1999; // Error

TypeAlias (타입 별칭)

특정 타입이나 인터페이스를 참조할 수 있는 타입 변수를 의미한다.
정의한 타입에 대해 나중에 쉽게 참고할 수 있게 이름을 부여하는 것과 동일하다.

// string 타입 사용
const name: string = 'capt';

// 타입 별칭 사용
type MyName = string;
const name: MyName = 'capt';

type Test = {
  a: number;
  b: number;
}

TypeAlias vs Interface

둘의 가장 큰 차이는 타입의 확장 가능 / 불가능 여부
-> Interface는 확장이 가능한데 반해, TypeAlias는 확장 불가능
TypeAlias 방식에서는 intersection(&), union(|) 키워드와 tuple 사용 가능
타입스크립트 공식문서에서는 interface를 사용하여 타입을 선언할 것을 권장한다.

interface Point{
  x: number;
  y: number;
  z: number;
};
type PartialPointX = { x: number };
type PartialPointY = { y: number };

// intersection
type IntersectionPoint = PartialPointX & PartialPointY;

// union
type UnionPoint = PartialPointX | PartialPointY;

// tuple
type Data = [number, string];

State with generic

타입스크립트에서 제네릭(Generic)을 사용하면, 컴포넌트나 함수 등에서재사용 가능한 코드를 작성할 수 있다. -> 여러 종류의 타입에 대응, 타입 안정성이 보장된다.
매개변수의 괄호 바로 옆에 화살괄호<>로 묶어서 별칭을 배치해 제네릭으로 만들 수 있다.

// 상태 관리를 위해 useState 훅을 사용할 때 제네릭을 활용
import React, { useState } from 'react';

function MyComponent() {
  const [state, setState] = useState<Array<string>>([]);
  
  // ...
}

위 코드에서useState<Array<string>>([]) 부분은 상태 값이 문자열의 배열이 될 것임을 명시적으로 지정 -> 이 상태와 관련된 모든 작업에 대해 타입 체크 수행이 가능함

// value와 setValue라는 두 가지 속성을 가진 제네릭 인터페이스
interface State<T> {
  value: T;
  setValue: (newValue: T) => void;
}

function useGenericState<T>(initialValue: T): State<T> {
  const [value, setValue] = useState<T>(initialValue);
  
  return { value, setValue };
}
// 예시
const stringState = useGenericState<string>('hello');
stringState.setValue('new String'); // OK

const numberState = useGenericState<number>(123);
numberState.setValue(456); // OK

제네릭(Generic)을 사용하여 상태(state)를 관리하는 useGenericState 함수와 그를 사용하는 예시코드이다.
useGenericState 함수는 제네릭 T를 인자로 받아서 초기값과 함께 상태값을 설정하고 반환한다.
어떤 타입의 상태라도 동일한 로직으로 관리할 수 있으며, 각각의 경우에 대해 타입 안정성을 보장한다.

useGenericState 함수를 사용하여 stringStatenumberState 상태를 생성하고, setValue를 통해 값을 변경한다.
stringState는 문자열 타입의 상태로 초기값을 'hello'로 설정하고, stringState.setValue를 사용하여 값을 'new String'으로 변경하는 것이 가능하다.
마찬가지로 numberState는 숫자 타입의 상태로 초기값을 123으로 설정하고, numberState.setValue를 사용하여 값을 456으로 변경하는 것이 가능하다.

0개의 댓글