...
타입 - Boolean
단순한 참(true) / 거짓(false) 값
let isBoolean: boolean;
isBoolean = true;
let isDone: boolean = false;
타입 - Number
정적 타입이라 해서 C / JAVA 처럼 int, float, double 타입은 없고, Javascipt의 number 자료형을 그대로 사용한다.
16진수, 10진수, 2진수, 8진수 리터럴도 지원한다.
let num: number;
let integer: number = 6;
let float: number = 3.14;
let hex: number = 0xf00d; // 61453
let binary: number = 0b1010; // 10
let octal: number = 0o744; // 484
let infinity: number = Infinity;
let nan: number = NaN;
function plus(num1: number, num2: number): number {
return num1 + num2;
}
타입 - String
작은따옴표('), 큰따옴표(") 뿐만 아니라 ES6의 템플릿 문자열도 string 타입에 포함 된다.
let red: string = 'Red';
let green: string = "Green";
let yourColor: string = 'Your color is' + green;
let myColor: string = `My color is ${red}.`;
function strings(str1: string, str1: string): string {
return str1 + str1;
}
타입 - Array
배열 타입은 두 가지 방법으로 쓸 수 있다.
첫 번째 방법은 배열 요소들을 나타내는 타입 뒤에 []를 쓰는 것이고,
두 번째 방법은 Array<> 배열 타입을 쓰는 것이다.
let fruits: string[] = ['Apple', 'Banana', 'Mango'];
// or
let fruits: Array<string> = ['Apple', 'Banana', 'Mango'];
// 오직 숫자 아이템만 허용
let nums:number[] = [100, 101, 102];
// 오직 문자 아이템만 허용
let strs:string[] = ['apple', 'banana', 'melon'];
// 오직 불리언 아이템만 허용
let boos:boolean[] = [true, false, true];
// 모든 데이터 타입을 아이템으로 허용 (any 타입 - 뒤에서 배움)
let someArr: any[] = [0, 1, {}, [], 'str', false];
// 특정 데이터 타입만 아이템으로 허용 (union 타입 - 뒤에서 배움)
let selects:(number | string)[] = [102, 'apple'];
// 나머지 매개변수(스프레드 연산자) 를 이용한 배열 반환 함수
function getArr(...args: number[]): number[] {
return args;
}
getArr(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
타입 - Tuple
튜플은 배열의 서브타입 이다.
튜플이라는 용어가 생소할지도 모르지만, 그냥 크기와 타입이 고정된 배열 이라고 이해하면 된다.
예를 들어, RGB 색상을 표현하기 위해 다음 예제처럼 튜플을 활용할 수 있을수 있다.
let rgbColor: [number, number, number] = [255, 255, 0];
이 처럼 항상 정해진 갯수의 요소를 가져와야 하는 배열을 지정해서 응용할 수 있다.
let x: [string, number]; // 튜플 타입으로 선언
x = ["hello", 10]; // 성공
x = [10, "hello"]; // 오류 (원소 타입이 안맞음)
x = ["hello", 10, 99]; // 오류 (원소 갯수가 안맞음)
let user: [number, string, boolean] = [1234, 'HEROPY', true];
console.log(user[0]); // 1234
console.log(user[1]); // 'HEROPY'
console.log(user[2]); // true
/* 2차원 튜플 */
let users: [number, string, boolean][];
// or
let users: Array<[number, string, boolean]>;
users = [[1, 'Neo', true], [2, 'Evan', false], [3, 'Lewis', true]];
타입 뿐만 아니라 값 자체를 고정시킬 수도 있다. (강한 타입)
/* 타입 뿐만 아니라 값 자체를 고정 */
let tuple: [1, number];
tuple = [1, 2];
tuple = [1, 3];
tuple = [2, 3]; // Error - TS2322: Type '2' is not assignable to type '1'.
단, 유의할점은 튜플은 정해진 타입의 고정된 길이 배열을 표현하지만 이는 할당(Assign)에 국한 된다는 점이다..push() 나 .splice() 등을 통해 값을 넣는 행위는 막을 수 없다. (이러한 행위가 되는 이유는 컴파일러의 멍청함이라고 치부하면 된다)
let tuple: [string, number];
tuple = ['a', 1];
tuple = ['b', 2];
tuple.push(3);
console.log(tuple); // ['b', 2, 3];
tuple.push(true); // Error - 그렇다고 해서 튜플에 정의되지 않는 타입을 넣을수는 없다.
// push() 함수를 사용하여 요소를 추가하는 경우 처음 할당된 값의 타입과 정확히 일치해야 한다.
타입 - Enum
enum은 C, Java와 같은 언어를 다뤄봤으면 한번쯤 들어보는 흔하게 쓰이는 타입으로 특정 값(상수)들의 집합을 의미한다.
위에서 배운 튜플 타입이 특정 타입이나 값을 고정하는 배열이라면, Enum은 특정 값을 고정하는 또다른 독립된 자료형이라고 보면 된다.
// 상수 집합
enum Avengers { SpiderMan, IronMan, Thor, Hulk }
let hero: Avengers = Avengers.SpiderMan; // 0
enum은 인덱스 번호로도 접근할 수 있다.
// 시스템에서는 { SpiderMan = 0, IronMan = 1, Thor = 2, Hulk = 3 } 이런식으로 내부적으로 인덱싱이 자동으로 되어있다고 이해하면 된다.
enum Avengers { SpiderMan, IronMan, Thor, Hulk }
let hero: Avengers = Avengers[0];
만약 원한다면 이넘의 인덱스를 사용자 편의로 변경하여 사용할 수도 있다.
// 직접 인덱스 번호를 정한다면, 시스템에서는 { SpiderMan = 2, IronMan = 3, Thor = 4, Hulk = 5}
// 이런식으로 내부적으로 인덱싱이 정해진 숫자 이후로 순차적으로 증가한다고 이해하면 된다.
enum Avengers { SpiderMan = 2, IronMan, Thor, Hulk }
let hero: Avengers = Avengers[2]; // SpiderMan
let hero: Avengers = Avengers[5]; // Hulk
보다 자세한 타입스크립트 Enum 타입에 대해 알고싶다면 다음 포스팅을 참고하길 바란다.
타입 - Object
자바스크립트에서의 object는 객체 뿐만 아니라 배열, 함수 까지 object로 포함한다.
타입스크립트에서도 마찬가지라서 기본적으로 typeof 연산자가 "object"로 반환하는 모든 타입을 뜻한다.
정확히 number, string, boolean, bigint, symbol, null, 또는 undefined가 아닌 나머지를 의미한다.
let obj: object = {};
let arr: object = [];
let func: object = function () {};
let nullValue: object = null;
let date: object = new Date();
이처럼 여러 타입의 상위 타입으로 인식되기 때문에 타입스크립트에서 object를 그대로 타입으로 쓰기에는 애로사항이 많다.
더군다나 다음과 같이 object 타입에 객체값을 주고 실제로 조회해 보면 에러가 나버린다.
const player: object = { name: 'nico' };
player.name; // Error
따라서 정말 객체에 타입을 지정해주고 싶다면 다음과 같이 객체 속성(Properties)들에 대한 타입을 개별적으로 지정하는 식으로 사용하면 된다.
let userA: { name: string, age: number };
userA = {
name: 'HEROPY',
age: 123
};
let userB: { name: string, age: number };
userB = {
name: 'inpa',
age: false, // Error
email: 'inpa@naver.com' // Error
};
하지만 이게 타입인지 객체인지 뭔지 가독성이 매우 좋지않은걸 느끼실 텐데, 이를 극복하기 위해 타입스크립트는 type 리터럴이라고 불리우는 alias 기능과 interface 라는 문법을 추가했다. (type 별칭과 인터페이스는 뒤에서 다룬다)
// type alias
type IUser = {
name: string,
age: number
}
let userA: IUser = {
name: 'HEROPY',
age: 123
};
let userB: IUser = {
name: 'inpa',
age: false, // Error
email: 'inpa@naver.com' // Error
};
// interface
interface IUser {
name: string,
age: number
}
let userA: IUser = {
name: 'HEROPY',
age: 123
};
let userB: IUser = {
name: 'inpa',
age: false, // Error
email: 'inpa@naver.com' // Error
};
타입 - Any
any 타입은 단어 의미 그대로 모든 타입에 대해서 허용한다는 의미이다.
우리가 자바스크립트에서 사용하던 변수의 타입이 사실 any라고 봐도 무방하다.
any 타입이 존재하는 이유는 애플리케이션을 만들 때, 알지 못하는 타입을 표현해야 하는 경우가 존재할 수 있기 때문이다.
예를들어 사용자로부터 받은 데이터나 서드 파티 라이브러리 같은 동적인 컨텐츠에서 변수나 함수를 다룰때, 왠만하면 공식문서에 설명이 잘 되어있겠지만 그래도 알수가 없을때 유용하게 사용된다.
let any: any = 123;
any = 'Hello world';
any = {};
any = null;
let list: any[] = [1, true, "free"];
list[1] = 100;
// 명시적으로 any 타입 지정
let product_id: any = 124981;
product_id = 'p9023412'; // any 유형이 설정되었으므로 어떤 유형도 값으로 할당 가능
// 암시적으로 any 타입 지정
let product_id;
product_id = 124981;
product_id = 'p9023412';
하지만 그렇다고 any 타입을 남용해서 사용하지 말자.
any 타입을 이곳저곳 쓸것이면 자바스크립트로 코딩하면 되지, 굳이 타입스크립트를 쓰는 이유가 없어지기 때문이다.
그리고 무엇보다 타입스크립트 컴파일의 보호장치를 잃어버릴수도 있게 된다.
예를 들어 다음과 같이 잘못된 연산을 컴파일이 경고를 안해주게 된다. (마치 자바스크립트 같다)
const a: any[] = [1, 2, 3, 4]; // 배열
const b: any = true; // 불리언
a + b; // 배열과 불리언을 더했는데 컴파일이 허용하고 있다..
강한 타입 시스템의 장점을 유지하기 위해 Any 사용을 엄격하게 금지하려면, tsconfig에 컴파일 옵션"noImplicitAny": true를 통해 Any 사용 시 에러를 발생시킬 수 있다.
타입 - Unknown
Unknown의 Un 이라고 해서 무언가 부정적인 뜻으로 보이지만, 어렵게 생각할 필요 없이 그냥 any와 같은 놈이다.
말그대로 Unknown은 알 수 없는 타입을 의미하며, any와 같이 모든 데이터 타입을 받을 수 있다.
let a: any = 123;
let u: unknown = 123;
그럼 모든 타입을 허용하면서 왜 any와 unknown을 구분했을까?
- any는 어떤 것이든지 타입을 허용한다는 뜻이다.
- unknown은 알 수 없다, 모른다의 어감이 강하다.
이둘의 차이점은 '엄격함' 에 있다.
예를 들어 any타입 같은 경우 아래와 같이 number 타입의 데이터를 넣고 string 타입의 메소드 length를 사용했을때 어떠한 에러를 발생시키지 않고 그냥 undefined를 반환한다.
let value : any = 10;
console.log(value.length); // undefined
하지만 unknown 타입은 any 타입과 동일하게 모든 값을 허용하지만, 할당된 값이 어떤 타입인지 모르기 때문에 함부로 연산을 할 수 없다는 특징을 가지고 있다.
그래서 다음과 같이 미리 에디터 자체에서 에러를 띄워준다.
let valueNum: unknown = 10;
let valueStr: unknown = 'Test';
console.log(valueNum.length); // 문제 발생
console.log(valueStr.length); // 문제 발생
이런 경우 자바스크립트에서 자주 쓰이는 typeof 연산자를 통해 타입을 검사해서 해결할수 있다.
let valueNum: unknown = 10;
if (typeof valueNum === "number") {
console.log(valueNum.length);
}
이처럼 any 대신 unknown 타입을 사용하면 체크를 해야 되는 코드는 많아지겠지만, 사전에 문제가 되는 부분을 방지할 수 있으므로 any 타입에 비해 안정적인 애플리케이션을 개발할 수 있게 된다.
타입 - Null / Undefined
자바스크립트에서도 undefined가 하나의 자료형이자 값이었던 것 처럼, 타입스크립트에서도 null과 undefined 타입이 있다.
let nullable: null = null;
let undefinedable: undefined = undefined;
기본적으로 null 과 undefined는 다른 모든 타입의 하위 타입으로 치부된다.즉, null과 undefined를 아무 여러 타입에 할당할 수 있다는 것을 의미한다.
다만 tsconfig.json에서 strick 모드가 아닐경우에만 가능하다.
/* strick 모드가 아닐경우에만 대입이 가능함 */
let num: number = undefined;
let str: string = null;
let obj: { a: 1, b: false } = undefined;
let arr: any[] = null;
let und: undefined = null;
let nul: null = undefined;
let voi: void = null;
컴파일 옵션인 --stricks 이나 --strictNullChecks를 사용하면, null과 undefined는 오직 any와 각자 자신들 타입에만 할당 가능하게 된다. (예외적으로 undefined는 void에 할당 가능합)
이 옵션은 불특정한 많은 일반적인 에러를 방지하는 데 도움을 주니, 가능한 경우 --strictNullChecks를 사용할 것을 권장하는 편이다.
strictNullChecks 컴파일 옵션
tsconfig.json에서 컴파일 옵션을 다음과 같이 true로 줬을 경우 일반적인 타입 변수에 null을 할당할수 없게 된다.
{
"strictNullChecks": true, /* 엄격한 null 검사 사용 */
}
let assign_name:string = null; // [오류] [ts] 'null' 형식은 'string' 형식에 할당할 수 없다.
if (!assign_name) {
assign_name = '미네랄';
}
만일 string 타입에 어쩔수없이 null 또는 undefined 값이 오게되어, 이들을 허용하고 싶은 경우 유니언 타입인 string | null | undefined를 사용할 수 있다. (any로 처리해도 되겠지만 비권장)
let assign_name: string | null | undefiened = null;
if (!assign_name) {
assign_name = '미네랄';
}
타입 - Never
never 타입은 number나 string 처럼 어떠한 자료형 값을 담기 위한 타입이 아니다.
never 타입은 타입스크립트에서 잘못된 것을 알려주기 위한 키워드로써, 단어 그대로 절대 발생할 수 없는 타입을 나타낸다고 보면 된다.
보통 다음과 같이 빈 배열을 타입으로 잘못 선언한 경우, never를 볼 수 있다.
이는 타입스크립트 초보자들이 가장많이 하는 실수이니 꼭 유의하자.
또한 never는 에러를 반환하는 함수 표현식에서 항상 오류를 발생시키거나 절대 반환하지 않는 반환 타입으로도 쓰일수 있다.
// 에러를 발생시키는 커스텀 never 타입 함수를 생성
function error(message: string): never {
throw new Error(message); // 함수는 리턴되지 않고 에러를 throw함
}
function fail() {
return error("Something failed"); // 커스텀 에러함수 호출
}
const result = fail(); // 반환 타입이 never로 추론된다.
never타입 역시 null나 undefiened 처럼 모든 타입에 할당 가능한 하위 타입이다.
하지만 반대로 어떤 타입도 never에 할당할수 없다 (never 자신은 제외).
function getError(): never {
throw new Error('ERROR');
}
let never_type: never;
never_type = 99; // 오류 발생: 숫자 값을 never 타입 변수에 할당할 수 없다.
// 함수의 반환 값이 never 타입 이기 때문에 오류가 발생하지 않는다.
never_type = getError();
타입 - Void
void 라는 단어는 C나 JAVA에서 함수에서 return 값이 없었을때 사용해본 경험이 있을 것이다.
그 void가 이 void 타입이 맞다.
void는 어떤 타입도 존재할 수 없음을 나타내기 때문에, any의 반대 타입 같다고 볼수 있다.
따라서 void는 보통 함수에서 반환 값이 없을 때 반환 타입을 표현하기 위해 쓰인다고 보면 된다.
// return 값이 없는 함수
function hello(n: number): void {
let sum: number = n + 1;
}
const hi: void = hello(1); // 값을 반환하지 않는 함수는 실제로는 undefined를 반환
console.log(hi); // undefined
만일 void를 함수가 아닌 변수 타입으로 정의한다면, void 타입 변수에는 undefined와 null만 할당이 가능해진다.
즉, void를 타입 변수를 선언하는 것은 유용하지 않다고 보면 된다.
let unusable: void = undefined;
unusable = null; // 성공, tsconfig에서 strictNullChecks 컴파일 옵션을 사용하지 않을때만
타입 - Literal
타입이라고 해서 number, string, Array 같은 자료형만을 넣는다고 생각하겠지만, 문자열과 숫자에 한해서 직접 값 자체를 타입으로도 선언이 가능하다.
숫자 리터럴 타입 (Numeric Literal Types)
예를 들어 다음과 같은 상수가 있다. 이 상수의 타입은 무엇일까?
const num = 3;
정수 값이 들어가있으니 당연히 :number 라고 생각하겠지만, 확인해보면 타입 3 이라는게 들어가있다.
위에서 언급했듯이 타입스크립트의 타입은 자료형 뿐만 아니라 값 자체(숫자와 문자 한정)를 타입으로 지정할수 있다. 이는 타입은 왠만하면 아주 정확하게 명시하는 것이 타입스크립트의 근본이기 때문이다.
유기적으로 생각해보면 이는 정당한 판단이다. 왜냐하면 const 상수는 한번 초기화 되면 값이 바뀔일이 없기 때문이다.
그래서 표현하자면 다음과 같이되는데 어차피 상수니 타입을 생략이 가능하다.
이를 타입 추론이라 배우며 다음 포스팅에서 자세히 다룰 예정이다.
const num: 3 = 3;
const num = 3; // 타입 생략
이를 cosnt 상수외에 다른 응용처는 이렇게도 사용이 가능하다. (그냥 number 타입으로 해도 되지만 좀더 확실하게 반환 타입을 정하고 싶을때)
// 1 ~ 6 까지 주사위 숫자를 반환 하는 함수 (주사위는 숫자 7이상 이 나올수 없다)
function rollDice(): 1 | 2 | 3 | 4 | 5 | 6 {
// ...
}
문자열 리터럴 타입 (String Literal Types)
문자열 리터럴 타입은 문자열에 값을 정확하게 지정할때 사용된다.
type Easing = 'ease-in' | 'ease-out' | 'ease-in-out';
function animate(dx: number, dy: number, easing: Easing) {
if (easing === 'ease-in') {
// ...
} else if (easing === 'ease-out') {
} else if (easing === 'ease-in-out') {
} else {
// null이나 undefined를 전달하면 필터링 실행
}
}
animate(0, 0, 'ease-in');
animate(0, 0, 'uneasy'); // 오류: "uneasy"는 여기서 허용하지 않습니다
문자열 리터럴 타입은 나중에 배울 객체 지향 함수의 오버로드를 구별하기 위해 같은 방법으로 사용할 수 있다.
function createElement(tagName: "img"): HTMLImageElement;
function createElement(tagName: "input"): HTMLInputElement;
// ... 더 많은 오버로드 ...
function createElement(tagName: string): Element {
// ... 이곳에 코드를 ...
}
타입 - Union
2개 이상의 타입을 허용하는 경우, 이를 유니언(Union)이라고 한다. (OR 의 의미로도 쓰인다.)
| (파이프)를 통해 타입을 구분하며, 괄호는 단일 타입일 때는 안써도 되지만 배열일 경우 씌워야 한다.
let union: string | number;
union = 'Hello type!';
union = 123;
union = false; // Error - TS2322: Type 'false' is not assignable to type 'string | number'.
// 배열에 문자열과 넘버만을 허용하는데 튜플과 달리 자유로움
// 배열 타입을 UNION으로 표현할때 괄호로 묶어 표현 안그러면 string | number[] 이런식으로 됨
let array: (string | number)[] = ['Apple', 1, 2, 'Banana', 'Mango', 3];
// Or
let array: Array<string | number> = ['Apple', 1, 2, 'Banana', 'Mango', 3];
function padLeft(value: string, padding: boolean | number) {
// ...
}
let indentedString = padLeft("Hello world", true);
Union 주의할 점
다음과 같이 introduce() 함수의 파라미터 타입을 Person, Developer 타입 별칭들을 유니온으로 합쳤다.
유니온 타입을 A도 될 수 있고 B도 될 수 있는 타입이지라고 생각해서, 파라미터의 타입이 Person도 되고 Developer도 될테니까 함수 안에서 당연히 이 인터페이스들이 제공하는 속성들인 age나 skill를 사용할 수 있겠지라고 생각할 수 있겠지만, 타입스크립트 관점에서는 introduce() 함수를 호출하는 시점에 Person타입이 올지 Developer타입이 올지 알 수가 없기 때문에 에러를 내뿜게 된다.
type Person = {
name: string;
age: number;
}
type Developer = {
name: string;
skill: string;
}
function introduce(someone: Person | Developer) {
someone.name; // O 정상 동작
someone.age; // X 타입 오류
someone.skill; // X 타입 오류
}
즉, tsc는 어느 타입이 들어오든 간에 오류가 안 나는 방향으로 확실하게 타입을 추론한다는 특성이 있다.
그래서 결과적으로 Person과 Developer 두 타입에 공통적으로 들어있는 속성인 name만 접근할 수 있게 되는 것이다.
좀더 응용하자면 함수에서도 리턴값을 유니온으로 사용하게 되면 에러를 내뿜는다.
모든 경우의 수를 고려해 x와 y 매개변수에 number가 들어오느냐 string이 들어오느냐 에따라 리턴값이 달라지니 유니온을 명시했지만, 컴파일러 입장에서는 옳지 않다는 것이다.
function add(x: string | number, y: string | number): string | number {
return x + y;
}
add(1, 2);
add('1', '2');
add(1, '2');
이 부분은 곰곰히 생각해보면 당연한 원리이다.
아래의 코드에서 string 및 number 타입의 result 변수에 add(1, 2) 의 값을 받아본다. 유니온 입장에서도 논리적으로도 옳다.
function add(x: string | number, y: string | number): string | number {
return x + y;
}
const result: string | number = add(1, 2);
result.charAt(1);
하지만 다음과 같이 이 역시 에러를 내뿜는다.
왜냐하면 컴파일러 입장에서는 result 변수가 string인지 number인지 확신이 안되니 문자열 메소드인 charAt() 실행에 대해서 경고를 해주는 것이다.
이런 부분은 함수 오버로딩을 통해 해결 가능하다.
타입 - Intersection
&(ampersand)를 사용해 2개 이상의 타입을 조합하는 경우, 이를 인터섹션(Intersection)이라고 한다.
위에서 배운 유니언을 마치 또는(Or) 과 같이 이해한다면, 인터섹션은 그리고(And) 와 같이 보면 된다.
인터섹션은 새로운 타입을 생성하지 않고 기존의 타입들을 조합할 수 있기 때문에 유용하지만, 자주 사용되는 방법은 아니다.
type Person = {
name: string;
age: number;
};
type Developer = {
name: string;
skill: number;
};
const heropy: Person = {
name: 'Heropy',
age: 36,
skill: 11 // Error - { name: string; age: number; skill: number; }' 형식은 'person' 형식에 할당할 수 없습니다. 개체 리터럴은 알려진 속성만 지정할 수 있으며 'person' 형식에 'skill'이(가) 없습니다
};
// 두 타입 별칭을 합쳐 하나의 { name: string, age: number, skill: number } 이라는 타입을 구성한다.
const neo: Person & Developer = {
name: 'Neo',
age: 85,
skill: 11,
};
위 처럼 타입을 & 교집합을 해서 타입을 추론하는 것보다, 그냥 새로운 타입을 하나 만들어 할당하는 것을 권장한다.
타입 - Type Alias
타입 별칭(Type Alias)은 사용자가 정의하는 타입 변수 이다.
다음과 같이 한줄로 복잡하고 기나긴 타입을 정의하면 가독성이 좋지 않기 때문에, type 별칭으로 타입 형태를 묶어둔 뒤 별칭을 타입명으로 선언해서 사용하는 방법이라고 보면 된다.
type alias 와 interface의 변수명은 대문자로 쓰는게 국룰이다.
let Dom: {version:string, el:(selector:string)=>void, css:(prop:string)=>void} = {
version: '0.0.1',
el(){},
css(){}
};
type Operation = {
version: string,
el: (selector:string) => void,
css: (prop:string) => void
}
let Dom: Operation = {
version: '0.0.1',
el(){},
css(){}
};
만일 이 타입 별칭이 어떤 타입 묶음이었는지 기억이 안난다면, 에디터 상의 프리뷰 상태로 확인해볼 수 있다.
타입 별칭을 선언하는 방법은 마치 변수와 비슷하다.
흔히 C나 JAVA 처럼 앞에 자료형을 선언하고 뒤에 자료형에 부합하는 값을 대입하는 것 처럼, 타입도 type 이라는 자료형을 선언하고 뒤에 타입값을 넣으면 된다.
int num = 123123;
string str = "hello";
// type 변수명 = 타입;
type Name = string;
type Age = number;
let name: Name = 'Tom';
let age: Age = 20;
타입 - Interface
인터페이스는 상호 간에 정의한 약속 혹은 규칙을 의미한다.
좀더 쉽게 말하자면 타입을 정의한 것들을 한데 모은 객체 타입이라고 말할 수 있다. 그래서 객체의 껍데기 혹은 설계도라고 불린다.
타입스크립트에서의 인터페이스는 보통 다음과 같은 범주에 대해 약속을 정의할 수 있다.
- 객체의 스펙(속성과 속성의 타입)
- 함수의 파라미터
- 함수의 스펙(파라미터, 반환 타입 등)
- 배열과 객체를 접근하는 방식
- 클래스
이처럼 인터페이스는 단순히 타입 지정 뿐만 아니라 자체 확장하여 활용도를 높일수 있다는 장점이 있다.
interface Person {
name: string;
age: number;
}
interface Developer extends Person { // 인터페이스 상속
skill: string;
}
function logUser(obj: Developer) {
console.log(obj.name);
console.log(obj.age);
console.log(obj.skill);
}
let person = {
name: 'Capt',
age: 28,
skill: 'typescript, javascript'
};
logUser(person);
[type alias vs interface 사용 선호도]
타입 별칭과 인터페이스는 얼핏보면 비슷해 보이지만, 이들의 가장 큰 차이점은 타입의 확장 가능 / 불가능 여부 이다.
인터페이스는 다양한 방법으로 확장이 가능한데 반해 타입 별칭은 확장이 불가능하다.
따라서 간단한 타입 집합으로 이용할때는 type alias를 쓰고, 가능한 interface로 선언해서 사용하는 것을 추천되는 편이다.
타입스크립트의 인터페이스 기능에 대해 상세히 학습하고 싶다면 다음 포스팅을 참고하길 바란다.
타입 - Generic
제네릭은 타입을 변수화 하였다고 생각하면 된다.
우리가 데이터를 직접 다루지않고, 변수라는 상자에 담아 사용하는 이유는 재사용성을 높이기 위해서다.
이처럼 타입을 마치 함수 파라미터 처럼 나중에 대입하도록 하여 재사용성을 높이기 위해 탄생한 타입이 제네릭 타입이라고 이해하면 된다.
제네릭의 선언 문법을 <T> 꺾쇠 괄호 기호를 이용한다. 안의 T 는 변수명으로서 아무 문자로 명명해줘도 상관없다.
type IsArray<T> = T[];
const numberArr: IsArray<number> = [1, 2, 3, 4, 5];
const stringArr: IsArray<string> = ['a', 'b', 'c', 'd', 'e'];
const mixArr: IsArray<string | number> = ['a', 2, 'c', 4, 'e'];
function getText<T>(text: T): T {
return text;
}
getText<string>('hi'); // 'hi'
getText<number>(10); // 10
getText<boolean>(true); // true
타입스크립트의 제네릭 기능에 대해 상세히 학습하고 싶다면 다음 포스팅을 참고하길 바란다.
타입간 대입 가능한 표
어떤 타입은 하위 타입이라 아무 타입에 넣을 수 있고, 어떤 타입은 넣을수 없고 워낙 복잡해서 표로 정리해보면 다음과 같다. 초록색 체크는 strict 모드가 false일때만 허용되는 것이므로 사실상 X 라고 봐도 무방하다.
표를 읽는 법은 다음과 같다.
"데이터( any → ) 가 들어갈수 있는 타입은 자기자신과 unknown ~ null 타입에 대입될수 있으며, never 타입에는 대입될 수 없다" 라고 해석 하면 된다.
# 참고 자료
https://github.com/ZeroCho/ts-all-in-one
https://heropy.blog/2020/01/27/typescript/
https://typescript-kr.github.io/pages/basic-types.html
https://yamoo9.gitbook.io/typescript/types
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.