본문 바로가기
Web/TypeScript

[TypeScript] 타입스크립트 개념 및 사용

by _eunji_ 2022. 5. 5.

타입스크립트 TypeScript 란?

Microsoft에서 개발한 오픈 소스 프로그래밍 언어로 자바스크립트의 단점을 보완하기 위해 만들어졌다.

자바스크립트는 동적 타입 언어로 런타임 속도는 빠르지만 타입 안정성이 보장되지 않는다. 따라서 대규모 애플리케이션을 개발하는데 어렵고 불편하다.

반면에 타입스크립트는 정적 타입 언어이기 때문에 컴파일 시 시간이 걸리지만 안정성이 보장된다. 즉, 타입스크립트는 타입을 선언하여 간편하게 에러를 잡을 수 있다.

타입스크립트는 자바스크립트의 상위 집합으로 자바스크립트의 한계를 해결한다.

 

 

타입스크립트를 쓰는 이유

  1. 동적 타입을 정적으로 선언할 수 있다.
  2. 타입 유추를 통한 타입 제어가 가능하다.
  3. 컴파일 시점에 오류를 포착할 수 있다.
  4. JavaScript에서 찾을 수 없는 추가 코드 기능을 제공한다.

 

동적타입을 정적으로 선언

// 자바스크립트
let a;
a = 1;
a = 'b';

 

// 타입스크립트
let a : number;

a = 1;
a = 'b'; // error

a는 number 타입으로 선언되었기 때문에 string형으로 선언 시 오류가 발생한다.

 

타입 유추를 통한 타입 제어

// 자바스크립트
const sum = (a, b) => {
	return a + b
}
sum(1, "2") // 12
// 타입스크립트
const sum = (a: number, b: number) =>
{
	return a + b
}
sum(1, 2) // 3

매개 변수 a,b의 자료형이 number이기 때문에 반환값의 자료형도 number임이 유추 가능하다.

 

 

타입이 필요한 이유

자바스크립트는 타입이 없기 때문에 실행 후 타입 에러를 확인할 수 있다. 반면 타입스크립트는 같은 코드에 대해 실행하기 전, 미리 에러를 확인할 수 있다.

즉, 자바스크립트의 런타임 단계에서 발생하는 타입 에러는 타입스크립트를 이용한다면 컴파일 단계에서 미리 확인하고 고칠 수 있다. 따라서 타입스크립트를 이용하면 타입 에러와 같은 개발자의 실수를 미리 방지할 수 있다.

 

 

TypeScript의 기본 Type

TypeScript는 JavaScript 코드에 변수나 함수 등 Type을 정의할 수 있다.

Type을 나타내기 위해서 타입 표기(Type Annotation)를 사용한다.

TypeScript의 Type은 다음과 같다.

  • 기본 자료형(primitive type)
  • 참조 자료형(reference type)
  • 추가 제공 자료형

 

기본 자료형 

- object 와 reference 형태가 아닌 실제 값을 저장하는 자료형

- primitive type 내장 함수를 사용 가능한 것은 자바스크립트 처리 방식 덕분

- 종류

  • string : 문자열
  • boolean : 참/거짓
  • number : 부동 소수 값
  • null : 값이 의도적으로 비어있는 상태
  • undefined : 아무 값이 할당되지 않은 상태
  • symbol (ES6 추가) 

 

참조 자료형

- 객체, 배열, 함수 등과 같은 Object형식의 타입

- 메모리에 값을 주소로 저장하고, 출력 시 메모리 주소와 일치하는 값을 출력

- 종류

  • object
  • array
  • function

 

object : 기본 자료형에 해당하지 않는 타입 (string, boolean, number, null, undefined를 제외한 타입)

function create(o: object): void{}
create({ prop: 0 }) // 성공
create([1, 2, 3]) // 성공
create("string") // error
create(false) // error
create(42) // error
create(null) // error
create(undefined) // error

 

array : 배열 저장 타입

let arr: number[] = [1, 2, 3]
let arr: Array<number> = [1, 2, 3] // 제네릭을 사용한 타입 표기 가능

 

 

추가 제공 자료형

- TypeScript에서 개발자의 편의를 위해 추가로 제공하는 타입

- 종류

  • tuple
  • enum
  • any
  • void
  • never

 

tuple : 길이와 각 요소의 타입이 정해진 배열을 저장하는 타입

let arr: [string, number] = ["Hello", 3];
arr[1].concat("!"); // Error, 'number' does not have 'concat’

// 정의하지 않은 index 호출 시 오류
arr[3] = "hi";
// Error, Property '3' does not exist on type '[string, number]'

arr[1]의 자료형은 number이기 때문에 concat함수를 사용할 수 없어 error가 발생하고,

arr[3]은 배열의 범위를 벗어났기 때문에 error가 발생한다.

 

enum : 특정 값(상수)들의 집합을 저장하는 타입

enum Car { BUS, TAXI, SUV };
let bus: Car = Car.BUS;
let bus: Car = Car[0]; // 인덱스 번호로 접근

// 인덱스를 사용자 편의로 변경
enum Car { BUS = 1, TAXI = 2, SUV = 3 };
let taxi: String = Car[2];
enum Car { BUS = 2, TAXI, SUV };
let taxi: String = Car[3];

 

any : 모든 타입 저장 가능, 컴파일 중 타입 검사를 하지 않음

let str: any = "hi";
let num: any = 10;
let arr: any = ["a", 2, true]

 

void : 보통 함수에서 반환값이 없을 때, any의 반대 타입 / 변수에는 undefined와 null만 할당하고, 함수에는 반환 값을 설정할 수 없는 타입

let unknown: void = undefined;
function sayHi(): void {
	console.log("hi");
}

 

never : 발생할 수 없는 타입, 항상 오류를 발생시키거나 절대 반환하지 않는 반환 타입 / 종료되지 않는 함수

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

neverEnd 함수는 무한 반복으로 함수가 종료되지 않는다.

// Error: A function returning 'never' cannot have a reachable end point.ts(2534)
// 자료형이 never로 선언되었는데 break로 반복문을 빠져나와 오류 발생
function neverEnd(): never {
	while (true) {
		break;
	}
}
// 항상 오류를 발생시키는 함수
function error(message: string): never {
	throw new Error(message);
}

 

Utility types

- TypeScript는 공통 타입 변환을 용이하게 하기 위해 유틸리티 타입을 제공한다.

- 유틸리티 타입은 전역으로 사용 가능하다.

- 종류

  • Partial<T>, Readonly<T>
  • Record<T>, Pick<T,K>
  • Omit<T,K>, Exclude<T,U>, Extract<T,U>
  • NonNullable<T>, Parameters<T>, ConstructorParameters<T>
  • ReturnType<T>, Required<T>

 

Partial<T> :

- 프로퍼티를 선택적으로 만드는 타입을 구성한다.

- 주어진 타입의 모든 하위 타입 집합을 나타내는 타입을 반환한다

interface Todo {
    title: string;
    description: string;
}
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
	return { ...todo, ...fieldsToUpdate };
}
const todo1 = {
    title: 'organize desk',
    description: 'clear clutter',
};
const todo2 = updateTodo(todo1, {
	description: 'throw out trash',
})

 

Readonly<T> : 프로퍼티를 읽기 전용(readonly)으로 설정한 타입 을 구성한다.

interface Todo {
	title: string;
}
const todo: Readonly<Todo> = {
	title: 'Delete inactive users',
};

// 사용 예: frozen 객체의 프로퍼티에 재할당 방지
todo.title = 'Hello'; // Error: Cannot assign to 'title' because it is a read-only property

 

Record<T> : 프로퍼티의 집합 K로 타입을 구성한다. 타입의 프로퍼티들을 다른 타입에 매핑시키는 데 사용한다.

interface PageInfo {
	title: string;
}

type Page = 'home' | 'about' | 'contact';

const x: Record<Page, PageInfo> = {
    about: { title: 'about' },
    contact: { title: 'contact' },
    home: { subTitile: 'home' },
// Error: '{ subTitile: string; }' is not assignable

	main: { title: 'home' }, // Error: main is not assignable to type 'Page'.
};

 

Pick<T,K> : 프로퍼티 K의 집합을 선택해 타입을 구성한다.

interface Todo {
    title: string;
    description: string;
    completed: boolean;
}
type TodoPreview = Pick<Todo, 'title' | 'completed'>;

const todo: TodoPreview = {
    title: 'Clean room',
    completed: false,
    description: 'description’
	// Error: 'description' is not assignable to type
};

 

Omit<T,K> : 모든 프로퍼티를 선택한 다음 K를 제거한 타입을 구성한다.

interface Todo {
    title: string;
    description: string;
    completed: boolean;
}
type TodoPreview = Omit<Todo, 'description'>;
const todo: TodoPreview = {
    title: 'Clean room',
    completed: false,
    description: 'description' // Error: 'description' is not assignable to type
};

 

Exclude<T,U> : T에서 U에 할당할 수 있는 모든 속성을 제외 한 타입을 구성한다

type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number

 

Extract<T,U> : T에서 U에 할당 할 수 있는 모든 속성을 추출 하여 타입을 구성한다.

type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T1 = Extract<string | number | (() => void), Function>; // () => void

 

NonNullable<T> : null 과 undefined를 제외한 타입이다.

type T0 = NonNullable<string | number | undefined>; // string | number
type T1 = NonNullable<string[] | null | undefined>; // string[]

 

Parameters<T> : 함수 타입 T의 매개변수 타입들의 튜플 타입을 구성한다.

declare function f1(arg: { a: number, b: string}): void
type T0 = Parameters<() => string>; // []
type T1 = Parameters<(s: string) => void>; // [string]
type T2 = Parameters<(<T>(arg: T) => T)>; // [unknown]
type T4 = Parameters<typeof f1>; // [{ a: number, b: string }]
type T5 = Parameters<any>; // unknown[]
type T6 = Parameters<never>; // never
type T7 = Parameters<string>; // 오류
type T8 = Parameters<Function>; // 오류

 

ConstructorParameters<T>

- 생성자 함수 타입의 모든 매개변수 타입을 추출한다.

- 모든 매개변수 타입을 가지는 튜플 타입(T가 함수가 아닌 경우 never)을 생성한다.

Type T10 = ConstructorParameters<ErrorConstructor>; // [(string | undefined)?]
type T1 = ConstructorParameters<FunctionConstructor>; // string[]
type T2 = ConstructorParameters<RegExpConstructor>; // [string, (string | undefined)?]
interface I1 {
	new(args: string): Function;
}
type T12 = ConstructorParameters<I1>; // [string]
function f1(a: T12) {
	a[0]
	a[1] // Error: Tuple type '[args: string]' of length '1' has no element at index '1'.
}

 

ReturnType<T> : 함수 T의 반환 타입으로 구성된 타입을 생성한다.

declare function f1(): { a: number, b: string }
type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<(s: string) => void>; // void
type T2 = ReturnType<(<T>() => T)>; // {}
type T3 = ReturnType<(<T extends U, U extends number[]>() => T)>; // number[]
type T4 = ReturnType<typeof f1>; // { a: number,b: string }
type T5 = ReturnType<any>; // any
type T6 = ReturnType<never>; // any
type T7 = ReturnType<string>; // 오류
type T8 = ReturnType<Function>; // 오류

 

Required<T> : T의 모든 프로퍼티가 필수로 설정된 타입을 구성한다.

interface Props {
    a?: number;
    b?: string;
};
const obj: Props = { a: 5 };
const obj2: Required<Props> = { a: 5 };
// Error: Property 'b' is missing in type '{ a:number; }'

 

 

TypeScript를 이용해 함수 사용하기

  • 함수를 정의할 때 사용되는 변수를 매개 변수라고 한다
  • 함수를 호출할 때 사용되는 값을 인수라고 한다.
  • 인자 값 == 매개변수 == Parameter

 

 

일급 객체(first-class object)

- 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 일급 객체라고 한다.

- JavaScript와 TypeScript의 함수는 일급 객체(first-class object)이다.

- 일급 객체의 조건

  1. 다른 함수에 매개변수로 제공할 수 있다.
  2. 함수에서 반환 가능하다.
  3. 변수에 할당 가능하다. 

 

 

함수 선언 방법 5가지

  1. 함수 선언식
  2. 함수 표현식
  3. 화살표 함수 표현식
  4. 단축형 화살표 함수 표현식
  5. 함수 생성자
// 1. 함수 선언식
function world(name) {
	return 'hello ${name}';
}

// 2. 함수 표현식
let world2 = function (name) {
	return 'hello ${name}';
}

// 3. 화살표 함수 표현식
let world3 = (name) => {
	return 'hello ${name}';
}

// 4. 단축형 화살표 함수 표현식
let world4 = (name) => 'hello ${name}';

// 5. 함수 생성자 => 되도록 사용 권장 X
let world5 = new Function("name",'return "hello "+ name');

 

 

TypeScript 함수 작성

  • TypeScript 함수 작성 시 반환 타입을 추론 하도록 하는 걸 권장한다.
  • 함수의 매개 변수와 인수의 타입이 호환 가능하게 작성한다.
  • 인수의 타입을 잘못 전달하면 에러가 발생한다.
// 1. 함수 선언식
function world(name : string) : string {
	return 'hello ${name}';
}

// 2. 함수 표현식
let world2 = function (name:string) : string {
	return 'hello ${name}';
}

// 3. 화살표 함수 표현식
let world3 = (name:String) : string => {
	return 'hello ${name}';
}

// 4. 단축형 화살표 함수 표현식
let world4 = (name:string) : string => 'hello ${name}';

 

 

타입 추론

  • TypeScript 컴파일러는 방정식의 한쪽에만 타입이 있더라도 타입을 추론할 수 있다.
  • 이러한 타입 추론 형태를 “contextual typing” 이라고 한다.
  • 이를 통해 프로그램에서 타입을 유지하기 위한 노력을 줄일 수 있다.
// 매개변수 x와 y는 number 타입
let f12: (baseValue: number, increment: number) => number = function (x, y) {
	return x + y;
}

 

 

함수의 매개변수

  • 기본 매개변수 (Parameter)
  • 선택적 매개변수 (Optional Parameter)
  • 기본-초기화 매개변수 (Default Parameter)
  • 나머지 매개변수 (Rest Parameters)

기본 매개변수

- 함수에 주어진 인자의 수는 함수가 기대하는 매개변수의 수와 일치해야 한다

function buildName(firstName: string, lastName: string) {
	return firstName +" "+ lastName;
}
let result1 = buildName("Bob"); // Error: Expected 2 arguments, but got 1
let result2 = buildName("Bob", "Adams", "Sr."); // Error: Expected 2 arguments, but got 3
let result3 = buildName("Bob", "Adams");

 

선택적 매개변수

- JavaScript에서는 모든 매개변수가 선택적으로, 인수가 없다면 undefined가 된다.

- TypeScript에서도 선택적 매개변수를 사용할 수 있다. (변수명 뒤에 ‘?’)

function buildName(firstName: string, lastName?: string) {
    if (lastName) return firstName +" "+ lastName;
    else return firstName;
}
let result1 = buildName("Bob");
let result2 = buildName("Bob", "Adams");
let result3 = buildName("Bob", "Adams", "Sr."); // Error: Expected 2 arguments, but got 3

 

기본-초기화 매개변수

- TypeScript에서는 값을 제공하지 않거나, undefined로 했을 때에 매개변수의 값 할당 가능

function buildName(firstName: string, lastName = "Smith") {
	return firstName +" "+ lastName;
}
let result1 = buildName("Bob"); // "Bob Smith"
let result2 = buildName("Bob", undefined); // "Bob Smith"
let result3 = buildName("Bob", "Adams"); // "Bob Adams"
let result4 = buildName("Bob", "Adams", "Sr."); // Error: Expected 1-2 arguments, but got 3.

 

나머지 매개변수

- 컴파일러는 생략 부호(...) 뒤의 인자 배열을 빌드해 함수에서 사용할 수 있다.

- 나머지 매개변수는 매개변수의 수를 무한으로 취급한다.

- 아무것도 넘겨주지 않을 수도 있다. 

function buildName1(firstName: string, ...restOfName: string[]) {
	// restOfName = [ 'Samuel', 'Lucas', 'MacKinzie' ]
	return firstName +" "+ restOfName.join(" ");
}
let employeeName = buildName1("Joseph", "Samuel", "Lucas", "MacKinzie"); // "Joseph Samuel Lucas MacKinzie"

 

 

 

'Web > TypeScript' 카테고리의 다른 글

[TypeScript] Generic, Union type, 제약 조건  (0) 2022.05.06

댓글