TIL 25 TypeScript - 타입 선언 및 종류

Leo·2021년 5월 10일
0

TypeScript

목록 보기
2/2
post-thumbnail

타입 지정

기본 타입

타입스크립트는 일반 변수, 매개 변수(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);

타입 선언

불린 : Boolean

단순한 참(true)/거짓(false) 값을 나타낸다.

let isBoolean: boolean;
let isDone: boolean = false;

숫자 : Number

모든 부동 소수점 값을 사용할 수 있다.
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;

문자열 : String

문자열을 나타낸다
작음따옴표, 큰따옴표 뿐만 아니라 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;

배열 : Array

순차적으로 값을 가지는 일반 배열을 나타낸다.
배열은 다음과 같이 두 가지 방법으로 선언할 수 있다.

// 문자열만 가지는 배열
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

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

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

Any는 모든 타입을 의미한다.
따라서 일반적인 자바스크립트 변수와 동일하게 어떤 타입의 값도 할당할 수 있다.
API같은 외부 자원을 활용해 개발할 때 타입을 단언할 수 없는 경우 유용하다.

let any: any = 123;
any = 'play game';
any = {};
any = null;

여러 값을 포함하는 배열을 나타낼 때 사용할 수도 있다.

const arr: any[] = [1, true, 'typescript'];

타입스크립트의 강한 타입 시스템의 장점을 유지하기 위해서 any사용을 엄격하게 금지하려면 컴파일 옵션 "noImplicitAny": true를 사용해 any 사용시 에러 발생시킬 수 있음

알 수 없는 타입: Unknown

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은 서로 할당할 수 있다.

객체: Object

기본적으로 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

기본적으로 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는 일반적으로 값을 반환하지 않는 함수에서 사용햔다.
: 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

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'

유니언(Union)

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 타입만 허용하기 때문에 에러.

인터섹션(Intersection)

&(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
}

함수(Function)

화살표 함수를 이용해 타입을 지정할 수 있다.
인수의 타입과 반환 값의 타입을 입력한다.

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');
};

What I Learned?

타입스크립트에서 쓰이는 타입들을 참고사이트를 보면서 하나하나 씩 쳐보았다. 한번 읽고 넘기는 것보다 쳐보는 것이 빠르게 적응되기 때문이었다.

느낀점은 자바와 C같이 정적인 언어처럼 컴파일단계에서 에러를 잡기 위해 데이터 타입을 엄격하게 정해놓는다는 것이다. 자바스크립트를 처음 접할 때 너무나 동적인 언어라서 이질감을 느꼈었다. 식별자에 변수를 할당하면 그 변수대로 데이터 형식이 정해지는 것이 그러한 기분의 원인이었다.

정수도 다 같은 정수가 아니고 int short long 처럼 다 다른 정수이기 때문이다.

공부를 하다보니 적응이 됐지만 디버깅을 할 때 console.log()로 찾아내는 것은 여전히 불편하긴 했다. 타입스크립트 공부를 이제 막 시작했지만 낯설지 않았고 더 깊이 있게 공부해야겠다고 생각했다.

Reference

profile
느리지만 확실하게

0개의 댓글