TypeScript
(타입스크립트)란TypeScript
의 등장 배경JavaScript는 처음에는 브라우저에서만 동작하는 스크립팅 언어로 만들어졌다.
let add = (x, y) => {
return x + y;
}
add(5, "7");
// 숫자 5와 문자열 "7"을 전달인자로 전달 결과는 "57"이 나온다.
JavaScript
는 함수나 변수의 타입을 명시적으로 지정하지 않아도 동작하는 경우가 많아 예상치 못한 결과를 초래하게 된다.
이런 문제점을 보완하기 위해 TypeScript라는 언어가 등장하게 되었다.
TypeScript
를 사용했을 시 장점TypeScript
는 정적타입 검사 기능을 제공.TypeScript
는 ES6의 문법을 포함한 최신 JavaScript 문법을 지원인터페이스(Interface)
, 제네릭(Generic)
, 데코레이터(Decorators)
등의 기능을 제공// 인터페이스(Interface)를 사용하여 코드의 가독성을 높인 예시
interface User {
id: number;
name: string;
}
function greetingUser(user: User) {
console.log(`Hello, ${user.name}!`)
}
const parkUser = {
id: 1,
name: "박해커"
};
greetingUser(parkUser);
User
인터페이스를 정의해 User
의 정보를 좀 더 쉽게 파악할 수 있다.greetingUser
함수에도 매개변수로 User
타입을 사용해 이 함수가 어떤 타입의 인자를 받고 있는지 명확히 표현하고 있다.TypeScript를 사용하면 코드의 가독성을 높일 수 있다.
타입을 명시함으로써 코드의 의도 또한 명확해지기 때문에 다른 개발자가 코드를 이해하고 수정하기 쉬워지며, 런타임 에러를 미리 방지할 수 있기 때문에 유지보수성 또한 높아진다.
TypeScript
의 타입TypeScript는 JavaScript와 거의 동일한 데이터 타입을 지원
참(true), 거짓(false) 값
let isShow: boolean = true;
let isDone: boolean = false;
정수와 실수의 구분 없이 Number 타입 하나로 표기
bigint
를 지원let number1: number = 5;
let number2: number = 0.7;
큰따옴표(")나 작은따옴표(')를 사용하여 문자열 데이터를 표현
백틱(``)
을 사용한 문자열인 템플릿 리터럴을 사용하면 여러 줄에 걸쳐 문자열을 작성할 수 있다.let firstName: string = "coding";
let lastName: string = 'kim';
let longString: string = `Kimcoding is a developer.
He is 20 years old.`
두 가지 방법으로 배열 타입을 선언해 사용할 수 있다.
//첫 번째 방법
let items: string[] = ["apple", "banana", "grape"];
//두 번째 방법
let numberList: Array<number> = [4, 7, 100];
[]
을 쓰는 것Array
를 먼저 작성한 뒤, <>
안에 배열의 요소들을 나타내는 타입을 작성튜플 타입을 사용하면 요소의 타입과 개수가 고정된 배열을 표현할 수 있다.
let user: [string, number, boolean] = ["kimcoding", 20, true];
// 모든 요소가 전부 같을 필요는 없지만,
// 배열의 index마다 타입이 정해져 있기 때문에 정확한 index에 접근할 필요가 있다.
console.log(user[2].toString());
// 이렇게 user[2]에 접근하게 되면,
// user[2]에 있는 요소는 boolean 타입이기 때문에 타입 에러가 발생.
JavaScript
에서도 튜플 타입을 지원하며, JavaScript
에서의 튜플 또한 여러 개의 값을 가진 배열을 나타내는 데에 사용한다.JavaScript
에서는 튜플 타입을 명시적으로 선언할 수 없기 때문에 개발자가 직접 튜플의 각 요소의 타입을 확인하고 유추해야 하므로 타입 에러가 더 쉽게 발생한다.TypeScript
의 등장 배경 중 하나인 타입 에러를 방지하고자 한 이유 중 하나이기도 하다.JavaScript
의 원시 타입에는 number
, string
, boolean
, undefined
, null
, symbol
이 있다.
let obj: object = {};
TypeScript
에서 object
타입은 모든 객체를 수용하는 타입.key-value
에 구체적인 타입까지도 지정할 수 있다.let user: {name: string, age: number} = {
name: "kimcoding",
age: 20
}
타입 검사를 하지 않고자 할 때 any 타입을 사용할 수 있다.
let maybe: any = 4;
---------------------
// any 타입을 사용하게 되면, 변수에 값을 재할당하는 경우,
// 타입을 명시한 변수와 달리 타입에 구애받지 않고 값을 재할당할 수 있게 된다.
---------------------
let obj: object = {};
//에러가 납니다.
obj = "hello";
let maybe: any = 4;
//정상적으로 동작합니다.
maybe = true;
---------------------
// 또한 엄격한 타입 검사를 진행하지 않기 때문에,
// 실제 할당된 값이 가지지 않는 메서드 및 프로퍼티로 접근해도 에러가 나지 않는다.
// 대신, 실제 할당된 값이 가지지 않는 메서드 및 프로퍼티이기 때문에 반환되는 값은 undefined입니다.
---------------------
let maybe: any = 4;
//undefined로 출력됩니다.
console.log(maybe.length);
---------------------
// 또한 any 타입은 타입의 일부만 알고, 전체는 알지 못할 때 유용.
// 예를 들어서 여러 타입이 섞인 배열을 받고자 할 때 유용.
---------------------
let list: any[] = [1, true, "free"];
//any로 다루고 있기 때문에 index 1번째 요소가 boolean 타입이지만 number 타입으로 재할당할 수 있습니다.
list[1] = 100;
TypeScript
의 함수JavaScript에서의 함수와 마찬가지로 TypeScript에도 함수는 JavaScript와 마찬가지로 기명 함수(named function)와 화살표 함수(arrow function) 등으로 만들 수 있다.
JavaScript
에서 함수
//named function
function add(x, y){
return x + y;
}
//arrow function
let add = (x, y) => {
return x + y;
}
TypeScript
로 다시 표현
//named function
function add(x: number, y: number):number {
return x + y;
}
//arrow function
let add = (x: number, y: number): number => {
return x + y;
}
TypeScript
에서 함수를 표현할 때는 매개변수의 타입과 리턴값의 타입을 명시
각 매개변수에 해당하는 타입을 작성하고, 리턴값의 타입을 괄호 뒤에 작성
반환되는 타입은 타입추론을 이용하여 생략할 수도 있다.
//named function
function add(x: number, y: number) {
return x + y;
}
//arrow function
let add = (x: number, y: number) => {
return x + y;
}
TypeScript
컴파일이 스스로 판단해서 타입을 넣어 줌void
를 사용하여 작성할 수 있다.let printAnswer = (): void => {
console.log("YES");
}
또한 TypeScript
는 JavaScript
와 달리 매개변수의 개수에 맞춰 전달인자를 전달해야 한다.
let greeting = (firstName: string, lastName: string): string => {
return `hello, ${firstName} ${lastName}`;
}
//에러가 납니다.
greeting('coding');
//정상적으로 작동합니다.
greeting('coding', 'kim');
//너무 많은 매개변수를 보내 에러가 납니다.
greeting('coding', 'kim', 'hacker');
만약 개발자가 전달인자를 전달하지 않거나, undefined
를 전달했을 때 할당될 매개변수의 값을 정해놓을 수도 있다.
이는 JavaScript에서의 default parameter
와 같은 동작
let greeting = (firstName: string, lastName: string ="kim"): string => {
return `hello, ${firstName} ${lastName}`;
}
//정상적으로 작동합니다.
greeting('coding');
//정상적으로 작동합니다.
greeting('coding', undefined);
//너무 많은 매개변수를 보내 에러가 납니다.
greeting('coding', 'kim', 'hacker');
// 때는 뒤의 인자로 undefined를 보내도 값은 “hello, coding kim”으로 반환
혹은 선택적 매개변수를 원한다면 매개변수의 이름 끝에 물음표(?)
를 붙임으로써 해결할 수도 있다.
let greeting = (firstName: string, lastName?: string): string => {
return `hello, ${firstName} ${lastName}`;
}
//정상적으로 작동합니다.
greeting('coding');
//정상적으로 작동합니다.
greeting('coding', 'kim');
//너무 많은 매개변수를 보내 에러가 납니다.
greeting('coding', 'kim', 'hacker');
// 그러나 이때는 greating('coding')과 같이 전달인자를 하나만 전달했기 때문에, 뒤의 매개변수는 undefined로 반환
TypeScript
의 연산자 활용 타입TypeScript는 연산자를 이용해 타입을 정할 수 있다.
|
연산자를 이용한 타입을 유니온(Union)
타입&
연산자를 이용한 타입은 인터섹션(Intersection)
타입(Union)
타입|
연산자를 이용||
(OR) 연산자와 같이 “A이거나 B이다”라는 의미의 타입function printValue(value: any): void {
if (typeof value === "number") {
console.log(`The value is a number: ${value}`);
} else {
console.log(`The value is a string: ${value}`);
}
}
printValue(10); // The value is a number: 10
printValue("hello"); // The value is a string: hello
value
매개변수의 타입을 any
로 정의number
인지 string
인지에 따라 if-else
문으로 나누어 출력any
를 사용하는 것은 JavaScript
로 작성하는 것과 큰 차이가 없기 때문에,
유니온 타입을 사용해 TypeScript
의 이점을 살리면서 코딩하는 것이 좋다.
function printValue(value: number|string): void {
if (typeof value === "number") {
console.log(`The value is a number: ${value}`);
} else {
console.log(`The value is a string: ${value}`);
}
}
printValue(10); // The value is a number: 10
printValue("hello"); // The value is a string: hello
(Union)
타입의 장점let value: string | number | boolean;
string | number | boolean
타입으로 선언된 변수는 문자열, 숫자, 불리언 타입 중 하나의 값을 가질 수 있다는 것이 명시적으로 표시되어 코드를 이해하기 쉽게 만들어 준다.(Union)
타입 사용 시 유의할 점유니온 타입인 값이 있으면, 유니온에 있는 모든 타입에 공통인 멤버들에만 접근할 수 있기 때문에 유의해야 한다.
인터페이스를 사용하여 Developer
와 Person
을 정의
interface Developer {
name: string;
skill: string;
}
interface Person {
name: string;
age: number;
}
function askSomeone(someone: Developer | Person) {
console.log(someone.name);
}
askSomenone
함수 내부에서는 Developer
와 Person
이 갖고 있는 공통 프로퍼티인 name
에만 접근할 수 있다.타입 가드(Type Guard)란?
TypeScript
에서 타입을 보호하기 위해 사용되는 기능 중 하나.
타입 가드는 특정 코드 블록에서 타입의 범위를 제한해 해당 코드 블록 안에서 타입 안정성을 보장.
// 타입 가드를 사용해 작성된 코드
function askSomeone(someone: Developer | Person) {
// in 연산자 : 타입스크립트에서 객체의 속성이 존재하는지를 체크하는 연산자
// in 연산자는 객체의 속성 이름과 함께 사용하여 해당 속성이 객체 내에 존재하는지 여부를 검사
if ('skill' in someone) {
console.log(someone.skill);
}
if ('age' in someone) {
console.log(someone.age);
}
}
in
연산자를 제공in
연산자는 객체의 프로퍼티 이름과 함께 사용(Intersection)
타입(Intersection)
은 둘 이상의 타입을 결합하여 새로운 타입을 만드는 방법&
연산자를 사용하여 표현interface Developer {
name: string;
skill: string;
}
interface Person {
name: string;
age: number;
}
type User = Developer & Person;
User
변수는 Developer
, Person
각각에 정의된 속성 모두를 받게 된다. interface Developer {
name: string;
skill: string;
}
interface Person {
name: string;
age: number;
}
function askSomeone(someone: Developer & Person) {
console.log(someone.age);
console.log(someone.name);
console.log(someone.skill);
}
Developer
와 Person
을 하나의 타입으로 묶었다.askSomeone
함수 내에선 정의된 프로퍼티에 전부 접근할 수 있다.그러나 인터섹션 타입은 타입 가드는 필요 없는 반면 Developer
와 Person
이라는 새로운 교집합을 만들어 내는 것이기 때문에, 전달인자를 전달할 때 모든 프로퍼티를 전부 보내줘야만 한다.
반대로 유니온 타입은 타입 가드를 해줘야 하지만 전달인자를 전달할 때 선택지가 생기게 된다.
interface Developer {
name: string;
skill: string;
}
interface Person {
name: string;
age: number;
}
function askSomeone(someone: Developer | Person) {
//이런 식으로 프로퍼티에 접근할 수 있습니다.
if ('skill' in someone) {
console.log(someone.skill);
}
if ('age' in someone) {
console.log(someone.age);
}
}
//유니온 타입은 전달인자를 전달할 때 선택지가 생깁니다.
askSomeone({name: '김코딩', skill: '웹 개발'});
askSomeone({name: '김코딩', age: 20});
function askSomeone2(someone: Developer & Person) {
//타입 가드를 사용하지 않아도 모든 프로퍼티에 접근할 수 있습니다.
console.log(someone.age);
console.log(someone.name);
console.log(someone.skill);
}
//그러나 인터섹션 타입으로 결합하게 된다면 전달인자를 전달할 때 선택지가 없습니다.
askSomeone2({name: '김코딩', skill: '웹 개발', age:20});
공감하며 읽었습니다. 좋은 글 감사드립니다.