[TS] Chapter 2. Typescript 기초 & 기본 자료형_Other Types

변진상·2023년 5월 24일
0

Typescript 학습

목록 보기
4/13

Chapter2 목표: union, 리터럴, 함수, 함수, 알 수 없는, 절대 타입에 대해 학습한다.

  1. Union
  2. Literal(string, number, boolean...)
  3. Type Alias
  4. function(return type)
  5. Function type(TS 자료형으로서의 Function)
  6. Callback function type
  7. unknown type
  8. never type

- Union type

유니언 타입은 두개 이상의 다른 타입을 조합해 만든 타입이다. 유니언 타입을 만들기 위해 조합한 타입들을 각각 유니언 타입의 멤버라고 한다.

function combine(input1: string | number, input2: string | number) {
  let result;

  if (typeof input1 == "number" && typeof input2 == "number") {
    // 유니언 타입을 이용해 함수를 구현한 후 런타임 타입 체크를 통해 argument들의 type의 종류에 따라 유연하게 기능을 구현할 수 있다.
    result = input1 + input2;
  } else {
    result = input1.toString() + input2.toString();
  }

  return result;
}

const combineNumber = combine(1, 44);
console.log(combineNumber); // => 45

const conbineName = combine("변", "진상");
console.log(conbineName); // => 변진상

- Literal type

리터럴 타입은 단순히 특정 변수나 매개변수가 아니다. 정확한 값을 가지는 타입이다. 일반적인 number, string, object... 등과 같은 타입 이외에도, 구체적인 문자열과 숫자 값을 타입 위치에서 지정할 수 있다.

위 사진과 같이 cnstNumb라는 변수는 타입할당을 하지 않았는데, const 키워드로 선언한 값이 변하지 않는 number값이다. 그래서 TS에서는 이를 2.8이라는 리터럴이 타입으로 지정된 것을 볼 수 있다.

리터럴 타입 자체는 별 의미가 없을 수 있으나, 유니언과 같이 쓰인다면 효과적으로 사용될 수 있다.
만약 함수 선언 당시 리터럴 타입으로 주어진 "string"이나 "number"타입이 아닌 argument가 주어질 경우 경고를 띄운다.

Boolean 타입도 리터럴타입이다. Boolean 리터럴 타입의 경우 true, false 단 두개의 타입만이 존재한다. Boolean 타입은 true | false 유니언타입의 별칭(alias)이다.

- Type alias

Type alias를 사용하면 타입의 별칭을 줄 수 있다. 다음과 같이 일반적인 core type의 별칭을 줄수 있다.

type NumberNumber = number;

그러나 단순히 한가지의 타입에 별칭을 지어 사용할 경우 코드를 쓰고 읽어감에 큰 혼란을 줄 수 있기 때문이 지양한다.

type alias는 특히 union type과 literal type의 조합에서 빛을 발한다.

function combineFunc(
  input1: string | number,
  input2: string | number,
  to: "toStr" | "toNumb"
) {
  if (to === "toStr") {
    return input1.toString() + input2.toString();
  } else {
    return +input1 + +input2;
  }
}

위 코드의 경우 union type으로 string | number가 반복되고 있다. 단 두 번만 쓰일 경우는 별 무리가 없어보이지만 만약 1억번 사용한다면 의미가 있을 것이다.

type Combinable = string | number;
type ToTo = "toStr" | "toNumb";

function combineFunc(input1: Combinable, input2: Combinable, to: ToTo) {
  if (to === "toStr") {
    return input1.toString() + input2.toString();
  } else {
    return +input1 + +input2;
  }
}

이렇게 코드를 간결하게 정리 할 수 있을 것이다.

전개구문을 이용해 응용할 수 있다.

type Role = "teacher" | "student" | "parents" | "dog";

const jack: { name: string; role: [Role, ...Role[]] } = {
  name: "Jack",
  role: [
    "teacher",
    "student",
    "parents",
    "parents",
    "parents",
    "parents",
    "dog",
  ],
};

console.log(jack);

타입 별칭을 이용해 객체타입에도 별칭을 붙일 수 있다.


/* -------------------------------------------------------------------------- */
/*                          Type Alias를 이용한 객체 타입 간소화                    */
/* -------------------------------------------------------------------------- */

type User = { name: string; age: number };

function getUserStatus(userObj: User) {
  return console.log(`name: ${userObj.name}, age: ${userObj.age}`);
}

const jack: User = {
  name: "잭",
  age: 1111,
};

console.log(getUserStatus(jack));

이렇게도 사용 가능...

- function(return type)

function add(num1: number, num2: number): number {
  return num1 + num2;
}
// number라고 명시할 수 있지만 TS가 add 함수가 number를 리턴함을 추론할 수 있기 때문에 생략하는 것도 좋다.

function printResult(num: number): void {
  console.log(num);
}
// 이 경우 undefined를 return하는데, void는 함수가 undefined나 아무것도 return하지 않음을 명시한다.

function printResult2(num: number): undefined {
  console.log(num);
  return;
}
// 이렇게 undefined를 리턴함을 명시할 수 있지만 함수 내에 return;을 작성해줘야 경고를 띄우지 않으며, 이렇게는 거의 사용하지 않는다.

- Function Type(Ts의 함수형 자료형)

아래 코드와 같이 다를 함수를 지시하는 변수(나는 이해를 위해 함수를 가리키는 pointer라고 했다.)나 Callback에서 사용할 수 있는 Function Type이 있다.

/* -------------------------------------------------------------------------- */
/*                              자료형으로서의 Function                           */
/* -------------------------------------------------------------------------- */

let funcPointer: Function;

funcPointer = add;
funcPointer = printResult;

이렇게 funcPointer가 Funtion 타입의 데이터를 할당할 것임을 명시했기 때문에, 기존에 작성한 add, printResult 둘 다 할당이 가능하다.
하지만 이를 좀 더 엄격하게 할당하기 위해 함수의 명세(parameter의 자료형, return type)를 자료형으로 명시할 수 있다.

/* -------------------------------------------------------------------------- */
/*                         더욱 엄격한 자료형 제공을 위한 함수 명세 이용                 */
/* -------------------------------------------------------------------------- */

let strictFuncPointer: (a: number, b: number) => number;

strictFuncPointer = add;

// strictFuncPointer = printResult; 
// !!! ERROR: 자료형으로 제공한 함수의 명세와 일치하지 않기 때문에 Error !!!

이렇게 에러를 띄운다!

- Callback Function

call back 함수의 type의 반환값이 void로 없다고 명시하더라도, 실제로는 callback 함수에서 데이터를 반환할 수 있다.

/* -------------------------------------------------------------------------- */
/*                   함수의 인자로 주어지는 Callback function의 자료형 명시            */
/* -------------------------------------------------------------------------- */

function addAndHandle(
  num1: number,
  num2: number,
  cb: (result: number) => void
) {
  const addedNum = num1 + num2;

  console.log(cb(addedNum)); // 콜백 함수의 반환값이 void라도 값을 반환할 수 있다.
}

const isReturn = addAndHandle(11, 22, (result) => {
  console.log(result);
  return true;
});

- unknwon Type

let anyVar: any;
let unknownVar: unknown;

anyVar = 3;
console.log(anyVar.toUpperCase()); // !!! 런타임 ERROR: 컴파일 당시에는 문제가 없다. !!!
console.log(typeof anyVar);

unknownVar = 2;
//console.log(unknownVar.toUpperCase());
// !!! ERROR: 컴파일 전에 unknown 자료형이기 때문에 타입체킹을 더 엄격히 하라고 에러를 띄운다.!!!

if (typeof unknownVar === "string") {
  console.log(unknownVar.toUpperCase());
}
// 이렇게 타입체킹을 거치면 에러를 띄우지 않는다.

console.log(typeof unknownVar);

any: 모든 타입의 값이 할당될 수 있다. TS에서 타입체킹을 유연하게 하기 때문에 컴파일 후 브라우저에서 실행하는 런타임시 에러를 띄울 수 있다.(예를 들어 number type의 데이터가 할당된 변수에 string의 메서드를 사용한 경우)

unknown: 모든 타입의 값이 할당될 수 있다. TS에서 타입체킹을 컴파일러가 엄격하게 하기 때문에, 위 코드와 같이 타입체킹을 위한 추가적인 코드를 요구하기도 한다.

- never type

never type 에러나 무한루프 등고 같이 코드가 중단 됨에 따라 이후의 코드에 도달할 수 없어 절대 값을 리턴할 수 없는 경우에 사용한다. void와 같지만 never라고 표기함으로써 sementic meaning을 추가해 코드 품질의 관점에서 의도를 더 분명히 할 수 있다.

/* -------------------------------------------------------------------------- */
/*                                 never type                                 */
/* -------------------------------------------------------------------------- */

function genError(message: string, code: number): never {
  throw { message: message, errorCode: code };
  //무한루프: while(true){}
}

genError("an error occurred!", 500);
profile
자신을 개발하는 개발자!

0개의 댓글