타입스크립트는 일반 변수, 매개 변수(Parameter), 객체 속성(Property) 등에 : TYPE과 같은 형태로 타입을 지정할 수 있다.
//기본 형태
function someFunc(a: TYPE_A, b: TYPE_B): TYPE_RETURN {
return a + b;
}
let some: TYPE_SOME = someFunc(1,2);
//실제 사용
function add(a: number, b: number) {
return a + b;
}
const sum: number = add(1, 2);
console.log(sum); // 3
변수 sum을 number가 아닌 string 타입으로 지정하면 컴파일조차 하지 않고 코드를 작성하는 시점에서 에러 발생
function add(a: number, b: number) {
return a + b;
}
const sum: string = add(1, 2); //error
console.log(sum);
단순한 참(true)/거짓(false) 값을 나타낸다.
let isBoolean: boolean;
let isDone: boolean = false;
모든 부동 소수점 값을 사용할 수 있다.
ES6에 도입된 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;
문자열을 나타낸다
작음따옴표, 큰따옴표 뿐만 아니라 ES6의 템플릿 문자열도 지원한다.
let str: string;
let red: string = 'Red';
let green: string = 'Green';
let myColor: string = `My color is ${red}`;
let yourColor: string = 'Your color is' + green;
순차적으로 값을 가지는 일반 배열을 나타낸다.
배열은 다음과 같이 두 가지 방법으로 선언할 수 있다.
// 문자열만 가지는 배열
let fruits: string[] = ["Apple", "Banana", "Mango"];
let fruits: Array<String> = ["Apple", "Banana", "Mango"];
// 숫자만 가지는 배열
let oneToSeven: number[] = [1, 2, 3, 4, 5, 6, 7];
let oneToSeven: Array<number> = [1, 2, 3, 4, 5, 6, 7];
유니언 타입(다중 타입)
의 '문자열과 숫자를 동시에 가지는 배열'도 선언할 수 있다.
let array: (string | number)[] = ["Apple", 1, 2, "Banana", "Mango", 3];
let array: Array<string | number> = ["Apple", 1, 2, "Banana", "Mango", 3];
배열이 가지는 항목의 값을 단언할 수 없다면 any를 사용할 수 있다.
let someArr: any[] = [0, 1, {}, [], "str", false];
인터페이스(Interface)나 커스텀 타입을 사용할 수도 있다.
interface IUser {
name: string;
age: number;
isVaild: boolean;
}
let userArr: IUser[] = [
{
name: "Neo",
age: 10,
isVaild: true,
},
{
name: "Lewis",
age: 64,
isVaild: false,
},
{
name: "Evan",
age: 123,
isVaild: true,
},
];
읽기 전용 배열을 생성할 수 있다. readonly
ReadonlyArray
타입 사용
let arrA: readonly number[] = [1, 2, 3, 4];
let arrB: ReadonlyArray<number> = [2, 4, 6, 8];
arrA[0] = 123;
Tuple 타입은 배열고 매우 유사하다. 차이점은 정해진 타입의 고정된 길이(length) 배열을 표현한다.
let tuple: [string, number];
tuple = ['a', 1];
tuple = [1, 'a'];
데이터를 개별 변수로 지정하지 않고, 단일 Tuple 타입으로 지정해 사용할 수 있다.
let userId: number = 1234;
let userName: string = 'juyoung';
let isValid: boolean = true;
let userA: [number, string, boolean] = [1234, 'juyoung', true];
console.log(userA[0]) // 1234
console.log(userA[1]) // 'juyoung'
console.log(userA[2]) // true
Tuple 타입의 2차월 배열 생성
let usersA: [number, string, boolean][];
let usersB: Array<[number, string, boolean]>
usersA = [[1, 'chisus', true], [2, 'jisu', false]];
값으로 타입을 대신할 수 있다.
let tupleA: [1, number];
tupleA = [1, 2];
tupleA = [2, 3]; // Error - TS2322: Type '2' is not assignable to type '1'.
//0번 째 요소가 1이라는 값으로 고정되어 있으므로 에러
Tuple은 정해진 타입의 고정된 길이 배열을 표현하지만 이는 할당(Assing)에 국한된다.
.push()
, .splice()
등을 통해 값을 넣는 행위는 막을 수 없다.
let tupleB: [string, number];
tupleB = ['a', 1];
tupleB = ['b', 2];
tuple.push(3);
console.log(tupleB); // ['b', 2, 3];
tupleB.push(true); // Error - TS2345: Argument of type 'true' is not assignable to parameter of type 'string | number'.
//string/number타입만 가지고 있기 때문에 boolean형 할당 불가
readonly
를 사용해 읽기 전용 튜플 생성 가능
let a: readonly [string, number] = ['rest', 123];
a[0] = 'work'; // Error - TS2540: Cannot assign to '0' because it is a read-only property.
Enum은 숫자 혹은 문자열 값 집합에 이름(Member)을 부여할 수 있는 타입으로, 값의 종류가 일정한 범위로 정해져 있는 경우 유용하다.
기본적으로 0부터 시작하며 1씩 증가한다.
enum Week {
Sun,
Mon,
Tue,
Wed,
Thu,
Fri,
Sat
}
console.log(Week.Mon); // 1
console.log(Week.Tue); // 2
수동으로 값을 변경할 수 있으며, 값을 변경한 부분부터 다시 1씩 증가한다.
enum Week {
Sun,
Mon=22,
Tue,
Wed,
Thu,
Fri,
Sat
}
console.log(Week.Mon); // 22
console.log(Week.Tue); // 23
Enum 타입은 역방향 매핑을 지원한다.
console.log(Week['Mon']); // 1
console.log(Week[1]); // 'Mon'
let day: Week = Week.Mon;
const re_Week: string = Week[1];
console.log(day); // 1
console.log(re_Week); // 'Mon'
Enum은 문자열 값으로도 초기화할 수 있다.
이 방법은 역방향 매핑을 지원하지 않으며 개별적으로 초기화해야 한다.
enum Color {
Red = 'red',
Green = 'green',
Blue = 'blue'
}
console.log(Color.Red); // red
console.log(Color['Green']); //green
Any는 모든 타입을 의미한다.
따라서 일반적인 자바스크립트 변수와 동일하게 어떤 타입의 값도 할당할 수 있다.
API같은 외부 자원을 활용해 개발할 때 타입을 단언할 수 없는 경우 유용하다.
let any: any = 123;
any = 'play game';
any = {};
any = null;
여러 값을 포함하는 배열을 나타낼 때 사용할 수도 있다.
const arr: any[] = [1, true, 'typescript'];
타입스크립트의 강한 타입 시스템의 장점을 유지하기 위해서 any사용을 엄격하게 금지하려면 컴파일 옵션 "noImplicitAny": true를 사용해 any 사용시 에러 발생시킬 수 있음
any와 같이 최상위 타입인 unknown은 알 수 없는 타입을 의미한다.
어떤 타입의 값도 할당할 수 있지만, unknown을 다른 타입에 할당할 수 없다.
let u: unknown = 123;
let test1: number = u; //알 수 없는 타입(unknown)은 모든 타입(any)을 제외한 다른 타입에 할당할 수 없습니다.
let test2: number = u as number; //타입을 단언하면 할당할 수 있다.
let test3: any = u; // any와 unknown은 서로 할당할 수 있다.
기본적으로 typeof 연산자가 'object'로 반환하는 모든 타입을 나타낸다.
컴파일러 옵션에서 엄격한 타입 검사(strict)를 true로 설정하면, null은 포함하지 않습니다.
let obj: object = {};
let arr: object = [];
let func: object = function () {};
let nullValue: object = null;
let date: object = new Date();
여러 타입의 상위 타입이기 때문에 그다지 유용하지 않다.
정확하게 타입을 지정하기 위해 객체의 프로퍼티의 타입을 개별적으로 지정할 수 있다.
let userA: { name: string, age: number} = {
name: 'juyoung',
age: 27
}
let userB: {name: string, age: number } = {
name: 'jisu',
age: false, // Error
email: 'wndud0647@gmail.com' // Error
}
반복적인 사용을 원할 경우, interface 나 type를 사용한다.
interface Users {
name: string,
age: number
}
let userA: Users = {
name: 'juyoung',
age: 27
};
let userB: Users = {
name: 'jisu',
age: 28,
mail: true // Error
}
기본적으로 null, undefined는 모든 타입의 하위 타입으로, 각 타입에 할당할 수 있다.
서로의 타입에도 할당 가능하다.
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;
컴파일 옵션에서 "strictNullChecks": true를 통해 엄격하게 Null과 undefined 서로의 타입까지 할당 할 수 없게 한다. 단, void에는 undefined할당 가능
let vod: void = undefined;
void는 일반적으로 값을 반환하지 않는 함수에서 사용햔다.
: void 위치는 함수가 반환 타입을 명시하는 곳이다.
function coding(msg: string): void {
console.log(`Happy ${msg}`);
}
값을 반환하지 않는 함수는 실제로는 undefined를 반환한다.
function coding(msg: string): void {
console.log(`Happy ${msg}`);
}
const javascript: void = coding('javascript'); // 'Happy javascript'
console.log(javascript); // undefined
// Error - TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
// 선언된 타입이 'any'나 'void'가 아닌 경우 return 값이 있어야 한다.
function hello(msg: string): undefined {
console.log(`Hello ${msg}`);
}
Never은 절대 발생하지 않을 값을 나타내며, 어떠한 타입도 적용할 수 없다.
function error(message: string): never {
throw new Error(message);
}
보통 다음과 같이 빈 배열을 타입으로 잘못 선언한 경우 Never을 볼 수 있다.
const never: [] = [];
never.push(3); //Argument of type '3' is not assignable to parameter of type 'never'
2개 이상의 타입을 허용하는 경우, 이를 유니언
이라 한다.
| (vertical bar)
를 이용해 타입을 구분하며, ()
은 선택 사항.
let union: (string | number);
union = 'Hello World';
union = 777;
union = false; // Error - TS2322: Type 'false' is not assignable to type 'string | number'.
// string, number 타입만 허용하기 때문에 에러.
&(ampersand)
를 사용해 2개 이상의 타입을 조합하는 경우, 이를 인터섹션
이라고 한다
인터섹션은 새로운 타입을 생성하지 않고 기존의 타입들을 조합할 수 있기 때문에 유용하지만 자주 사용되지는 않는다.
interface User {
name: string,
age: number
}
interface Validation {
isValid: boolean
}
const testCase: User = {
name: 'juyoung',
age: 27,
isValid: true // Error - TS2322: Type '{ name: string; age: number; isValid: boolean; }' is not assignable to type 'User'.
};
const testCase2: user & Validation = {
name: 'jisu',
age: 30,
isValid: true
}
화살표 함수를 이용해 타입을 지정할 수 있다.
인수의 타입과 반환 값의 타입을 입력한다.
let myFunc: (arg1: number, arg2: number) => number;
myFunc = function(x, y) {
return x + y;
}
myFunc(1, 2) // 3
let noneFunc: () => void;
noneFunc = function () {
console.log('hihi');
};
타입스크립트에서 쓰이는 타입들을 참고사이트를 보면서 하나하나 씩 쳐보았다. 한번 읽고 넘기는 것보다 쳐보는 것이 빠르게 적응되기 때문이었다.
느낀점은 자바와 C같이 정적인 언어처럼 컴파일단계에서 에러를 잡기 위해 데이터 타입을 엄격하게 정해놓는다는 것이다. 자바스크립트를 처음 접할 때 너무나 동적인 언어라서 이질감을 느꼈었다. 식별자에 변수를 할당하면 그 변수대로 데이터 형식이 정해지는 것이 그러한 기분의 원인이었다.
정수도 다 같은 정수가 아니고 int
short
long
처럼 다 다른 정수이기 때문이다.
공부를 하다보니 적응이 됐지만 디버깅을 할 때 console.log()
로 찾아내는 것은 여전히 불편하긴 했다. 타입스크립트 공부를 이제 막 시작했지만 낯설지 않았고 더 깊이 있게 공부해야겠다고 생각했다.