3주차 로그 - 타입 스크립트

이태형·2024년 6월 29일

Growth Log

목록 보기
2/18

React 책을 선택할 때, 일부로 타입스크립트를 사용하는 책을 선택해서 공부했다.
타입스크립트를 많이 사용한다고 하는데, 타입스크립트는 무엇인지 공부하기로 했다.

등장 배경

  • 자바스크립트가 널리 사용되면서 버그가 많이 발생
    • 자바스크립트는 동적 타입 언어로 변수에 어떠한 데이터 타입의 값도 할당이 가능
    • 별도의 타입 체크가 없어 값을 할당하는 시점에 변수의 타입이 동적으로 결정되고, 언제든지 자유롭게 변경이 가능
    • 유연성이 높다는 장점이 있지만 신뢰성이 떨어지는 단점이 존재
    • 개발자가 데이터 타입을 오해한 채 버그를 일으키는 코드 생길 수 있음
    • 또한 자바스크립트는 존재하지 않는 프로퍼티의 접근을 허용함
    • 위와 같은 사례들로 개발자가 코드를 짜는 동안에는 에러를 확인할 수 없고, 실행 중에 의도와 다른 결과를 야기함
  • 자바스크립트를 포함하여 정적 타입 언어로 탄생한게 타입스크립트
    • 정적 타입 언어는 실행되기 전에 컴파일 단계에서 코드의 오류를 검출
    • 자바스크립트의 문제점을 보완할 수 있음
    • 자바스크립트의 상위 집합 언어 ( JavaScript 문법 + 타입 )
  • 브라우저는 타입스크립트 파일을 읽을 수 없어서 타입스크립트로 문서를 작성하면 컴파일러를 통해 자바스크립트로 변경됨
// javaScript
console.log(4 / [] ) ; => NaN 출력
let a = (4 ; => a는 4

//typeScript
console.log(4 / [] ) ;  => 컴파일 에러
let a = (4 ;  => 컴파일 에러

설치

npm install -g typescript

.ts 와 .tsx 차이점

  • .ts 는 타입스크립트만 사용하는 경우
    • JSX 문법 사용 불가, 오직 타입스크립트만 사용 가능
  • .tsx 는 react component와 같이 사용할 경우
    • JSX 문법 사용 가능

**JSX 란?
JavaScript XML 의 약자로 JavaScript를 확장한 문법

  • 자바스크립트에서 HTML 문법 사용 가능
  • 리액트로 프로젝트를 개발할 때 사용되므로 공식적인 자바스크립트 문법은 아님
  • 브라우저에서 실행하기 전에 바벨을 사용하여 일반 자바스크립트 형태의 코드로 변환됨**

특성

  • 구문
    • JS의 구문이 허용되는 JavaScript 상위 집합 언어
  • 타입
    • 자바스크립트에는 없는 타입스크립트만의 고유한 개념
    • 자바스크립트와 호환되어야 하기 때문에 자바스크립트가 사용하는 타입과 별도 타입이 제공됨
    • 종류
      • number ( JS의 Number와 호환)
      • boolean (JS의 Boolean과 호환)
      • string (JS의 String과 호환)
      • object (JS의 Object와 호환)
      • array
      • tuple
      • enum
      • any
        • 모든 타입을 허용, 정해지지 않은 변수 지정 가능
        • 정적 타입 언어의 매커니즘과 일치하지 않으므로 사용을 지양
      • void
      • null
      • undefined
      • unknown
      • never
        • 도달이 불가능한 코드
  • 런타임 특성
    • JavaScript 의 런타임 특성을 가짐
    • 0 으로 나누는 행동을 예외 처리하지 않고 Infinity 값을 반환하는 특성
    • TypeScript 가 코드에 타입 오류가 있음을 검출해도, JavaScript 코드를 TypeScript 로 이동시키는 것은 같은 방식으로 실행시킬 것을 보장하는 것
  • 삭제된 타입
    • 컴파일러가 코드 검사를 마치면 타입을 삭제해서 결과적으로 컴파일된 코드를 만드는데 이 코드에는 타입 정보가 없음
    • 컴파일 도중에는 타입 오류가 표출될 수 있지만, 타입 시스템 자체는 프로그램이 실행될 때 작동하는 방식과 관련이 없음
    • 추가 런타임 라이브러리를 제공하지 않음, JavaScript 와 같은 표준 라이브러리를 사용하므로 TypeScript 관련 프레임워크를 추가로 공부할 필요 없음

타입 선언

타입 주석

  • 변수를 선언한 후 콜론 뒤에 타입과 함께 세미콜론을 붙임
  • 타입을 선언해준 변수는 선언된 타입과 다른 타입의 변수값으로 변경하려하면 오류 발생
// 기본적인 타입 표기
let name: string; 
let age: number;

타입 정의

  • 객체 생성
    • name: string 과 id: number 을 포함하는 추론 타입 객체 생성
const User {
	name: "Henry",
	id : 0 
}
  • 인터페이스 생성
    • 새로운 타입을 정의하는 또 다른 방법
    • 객체의 형태를 명시적으로 나타냄
interface User {
	name: string, 
	id: number
}
// interface 의 형태를 따르는 새로운 객체 생성
// 정의된 interface 에 맞지 않는 객체를 생성하면 경고
const user: User {
	name: "Henry",
	id: 0 
}

// 인터페이스는 함수에서 매개변수와 리턴 값을 명시하는 데 사용 가능 
function getAdminUser(): User {

}

function deleteUser(user: User) {

}

// 함수 스펙 지정
interface AddNumber {
	(x: number, y: number): number; // return 해주는 값이 없으면 void
}

let addNumber: AddNumber = (x, y) => {
	return x + y;
}

addNumber(10, 10); // result: 20
  • readonly 읽기 전용
    • 값을 할당한 후 변경할 수 없는 속성을 의미
    • ReadonlyArray 를 사용하여 읽기 전용 배열도 생성 가능
interface User {
	readonly name: string;
}

let Users: ReadonlyArray<string> = ["철수", "영희"];  // 변경 불가
  • 클래스 생성
    • 객체 지향 프로그래밍 지원
class UserAccount {
	name: string; 
	id: number; 
	constructor(name: string, id: number) {
		this.name = name;
		this.id = id;
	}
}

const user: User = new UserAccount("Murpy", 1);

타입 추론

  • 타입 지정 없이 변수를 생성하면서 특정 값을 할당하는 경우, 컴파일러가 우측 값에 따라 해당 변수의 타입을 지정
let a = true; // a의 타입을 boolean 으로 판단
let b = 1; // b의 타입을 number로 판단
let c = 'hello'; // c의 타입을 string 으로 판단
let d = {}; // d의 타입을 object로 판단 

// 타입스크립트 컴파일러가 타입을 유추할 수 있는 것에 중복하여 명시적으로 타입을 지정하는 것은 피해야 함
let name: string = '다은' 

유니온 타입

  • 하나의 변수에 지정할 수 있는 타입이 여러 개일 때 사용
let a: string | number; 

type MyBool = true | false;
  • 가장 많이 사용되는 형태
type WindowStates = "open" | "closed" | "minimized"
type LockStates = "locked" | "unlocked"
  • 인터페이스 유니온
    • 공통으로 선언된 속성만 사용 가능
    • 이럴 때 필요한 것이 유니온 타입가드
interface Ujin {
	name: string;
	age: number;
}

interface Dabin {
	name: string; 
	character: string; 
}

function combine(person: Ujin | Dabin) {
	person.name; // 정상
	person.age; // Error
	person.character; // Error
}
  • 유니온 타입가드
    • 선언한 변수나 객체를 사용하는 경우, 그대로 사용하면 오류가 발생할 수 있음
    • 타입스크립트는 유니온 타입을 이해할 뿐, 타입 내에 무엇이 있는지 분석하지 못함
    • 이런 경우, 런타임 타입 검사를 추가하여 타입이 어느 쪽에 해당하는지 판정을 해줘야함
function combine(input1: number | string. input2: number | string) {
	let reulst;
	if (typeof input1 === 'number' && typeof input2 === 'number' ) {
		result = input1 + input2; 
	} else {
		result = input1.toString() + input2.toString();
	}
	return result;
}

const combine(user: Ujin | Dabin) {
	if (user instanceof Ujin) {
		user.jjeu_jjeu(); 
	} else {
		user.bong_gug();
	}
}

제네릭 (타입 별칭)

  • type 키워드를 사용하여 새로운 타입 선언 가능
  • 타입 별칭을 사용하여 이미 존재하는 타입에 다른 이름을 붙여 사용 가능
type Centimeter = number;
type Kilogram = numbger; 
type NumberArray = Array<number>; 
type StringArray = Array<string>;

type Student = {
	name: string; 
	height: Centimeter; 
	weight: Kilogram; 
}

let student: Student = {
	name: "daeun",
	height: 153,
	weight: 45
}

인터페이스와 타입 별칭의 차이

  • 가장 큰 차이는 타입의 확장 가능, 불가능 여부

선언적 확장

  • 인터페이스는 새로운 속성을 추가하기 위해 같은 이름으로 재 정의하여 확장 가능
  • 타입 별칭을 불가능, 에러가 발생함
interface User {
	name: string;
}

interface User {
	age: number;
}

// User 에는 name, age 존재

type User {
	name: string; 
}

type User { 
	age: number;
} // Error

인터페이스 확장

  • extends 를 사용하여 인터페이스 간 확장 가능
interface User {
	name: string;
}

interface UserInfo extends User {
	age: number;
}

let person: UserInfo = {
	name: "철수", 
	age: 20,
}

interface User {
	name: string
}

interface Age {
	age: number;
}

// 인터페이스를 여러개 상속 가능
interface UserInfo extends User, Age {
	gender: string;
}

// 인터페이스는 타입을 상속받을 수 있음
// 단 리터럴 타입과 유니온 연산자를 사용한 타입은 상속 불가
type User = {
	name: string;
	age: number;
}

interface UserInfo extends User  {
	
}

타입 별칭 확장

type User = {
	name: string;
}

type UserInfo = User & {
	age: number; 
};

let newUser: UserInfo = {
	name: "영희", 
	age: 20
};

// 타입 -> 인터페이스 확장
interface User {
	name: string;
}

type UserInfo = User & {
	age: number;
}

인터페이스 VS 타입 별칭

  • 가능하다면 인터페이스를 사용하고, 인터페이스로 표현할 수 없거나 유니온, 튜플을 사용해야 하는 상황일 때만 타입 별칭 사용 권장

구조적 타입 시스템

  • 타입스크립트 핵심 원칙 중 하나는 타입 검사가 값이 있는 “형태” 에 집중
    • 형태 일치에는 일치시킬 객체의 필드의 하위 집합만 필요
  • 이는 덕 타이핑(duck typing) , 구조적 타이핑 이라고 불림
interface Point {
	x: number;
	y: number; 
}

function printPoint(p: Point) {
	console.log(`${p.x}, ${p.y}`);
}

// point 변수는 Point 타입으로 선언된 적이 없지만, TypeScript는 타입 검사에서
// point의 형태와 Point 의 형태를 비교
// 같은 형태이기 때문에 통과
const point = { x: 12, y: 16 };
printPoint(point);

const point2 = { x: 12, y: 26, z: 89 };
printPoint(point3); // prints "12, 26"

class VirtualPoint {
  x: number;
  y: number;
  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
}

const newPoint = new VirtualPoint(13, 56); 
printPoint(newPoint); // prints "13, 56"

여러 타입

배열

  • 배열 타입(array type) 과 제네릭 배열 타입(generic array type) 두 가지 형태로 나뉨

Array Type

  • 타입스크립트 0.9 버전부터 지원되었으며, 요소 타입에 대괄호 [] 를 사용해서 선언
  • 내장 타입인 number, string, boolean 뿐만 아니라 class, interface 도 사용 가능
    • 배열 요소 모두가 number 타입이라면 number[] 형태로 선언해야 함
let list: number[] = [1, 2, 3, 4, 5];
  • 유니온 타입 선언도 가능
let member: (string | number | boolean | null)[] = ["김멋사", 10, true, null]; 

제네릭 배열

  • Array 형태로 선언, 이 때 Type 은 저장할 타입을 의미
let str: Array<string | number> = ["김멋사", 10];
let str2: typeof str = ["김멋사", 20]; // 타입 쿼리
  • 익명 형식 함수로 타입 지정
let arr: Array<() => string> = [() => "라이캣", () => "김멋사" ];
console.log(arr[0]()); // "라이캣" 출력

튜플(Tuple)

  • n개의 요소에 대응하는 타입
  • [튜플 타입] = [배열]
  • 지정한 타입 만큼 배열에 개수를 고정
let member: [string, number] = ["김멋사", 10] ; 

객체 타입

  • 타입스크립트는 객체를 선언할 때 어떤 타입인지 명확하게 정의해야 함
  • 타입을 지정하지 않으면 자동으로 any 타입으로 지정됨
const student1: object= {};
const student2 = {}; // any 타입

옵션 속성

  • 특정 필드에 ? 를 붙이면 필수로 값을 넣어주지 않아도 됨
const cat: {type: string, age?: number} = {
	type: 'Persian'
};

cat.age=2;

열거형(Enums)

  • 비슷한 종류의 아이템들을 함께 묶어서 표현할 수 있는 수단
  • 숫자 또는 문자열 값 집합에 이름을 부여할 수 있는 타입
  • 이름은 첫 문자는 대문자, 키의 첫 문자도 대문자로 표시
  • 문자열에서 문자열로 매핑, 문자열에서 숫자로 매핑하는 두 가지 방법이 있음
enum Class {
	Rock,
	Scissors,
	Pager
}

숫자 열거형(Numeric Enums)

  • 값을 지정하지 않는 경우, 이전 값에서 +1 한 값으로 지정됨
  • 모두 지정하지 않은 경우, 기본적으로 0부터 시작해서 1씩 증가함
enum Class {
	Rock = 0; 
	Scissors = 100 + 1;  // 101
	Pager // 102
}

문자열 열거형(String Enums)

  • 문자열 또는 다른 문자열 열거형으로 상수를 초기화해야 함
  • 숫자 열거형처럼 값이 증가하지는 않지만 값을 읽기 쉽다는 장점이 있음
enum Game {
	Rock = "ROCK", 
	Scissors = "SCISSORS",
	Pager = "PAPER"
}

이종 열거형

  • 문자열과 숫자 값을 혼합하여 사용
enum Game {
	Rock = "Rock", 
	Scissors = 2, 
	Paper
}

const enums

  • 값이나 키로 열거형에 접근할 때 존재하지 않는 키에도 접근할 수 있는데, 그러면 불안정한 결과를 초래할 수 있어 const enum 을 사용
const enum Game {
	Rock,
	Scissors,
	Paper
}

0개의 댓글