본문 바로가기

TypeScript

20210505 TypeSciprt 02 TS에서 활용하는 type(Object, Array, Tuple, Any, Unknown, Never, Void)

TypeScript02

Object

  • 일반적으로 실제 값을 갖는게 아닌 값을 가진 곳을 가르키는 정보를 가짐
  • TS에서 object는 다른 의미로 사용됨
  • object type는 primitive가 아닌 type이라고 함
  • 즉, oject type <-> primitive type

object literal를 활용하여 만드는 경우

  • object가 아닌 object literal type임, 지정한 타입 그대로가 타입임
  • literal 모양으로 type을 표현
const person1 = { name: "Tom", age: 26 };
//person1 의 type은 object가 아님
// person1은 "{name: string, age: number}" 타입 임

Object 인 전역 내장 객체를 활용하여 만드는 경우

  • object type이거나 null 인 인자를 받음
  • 들어오는 인자는 null 또는 primitive 가 아닌 object type이어야 함
const person2 = Object.create({ name: "jerry", age: 28 });
  • object type에는 string, bool, number, symbol, null, undefined, bigint 는 넣을 수 없으므로 해당 primitive를 제한하고 싶을 때 사용
let obj2: object = {};

obj2 = { name: "tom" };
{
} // (O)

obj2 = [{ name: "tom" }]; // (O)
// array도 object의 일종이라서 넣을 수 있음

ogj2 = "string"; // (X)
ogj2 = 12; // (X)
// 등등..

Array

  • js에서 array는 객체임
  • Array의 경우 공통의 type으로 묶는게 좋음
  • 사용방법 : Array<타입> 또는 타입[]

타입[]

let list: number[] = [1, 2, 3];
let list2: (number | string)[] = [1, 2, 3, "4"]; // union 활용 가능

Array<타입> (충돌 가능성이 있어서 자제)

let list1: Array<number> = [1, 2, 3];

Tuple

  • 각 인덱스마다 type을 줄수 있음 (길이도 일치해야 함)
  • 즉, 순서 길이 모두 일치 해야함
let x: [string, number];

x = ["hello", 39];

const person: [string, number] = ["Tom", 25];

// 잘못된 사용

x = [35, "Not good"]; // 순서 error

x[2] = "word"; // 길이 error

x = ["hello"]; // 길이 error

const [first, second, third] = person; // third에는 받아올 수 없음

any

  • 어떤것이 될지 모르기 때문에 어떤 것이든 할당 가능하다. 라는 느낌
  • return type 지정
  • 최대한 쓰지 않는게 좋음 -> 컴파일 타임에 타입체크가 정상적으로 이뤄지지 않기 때문에
  • 그래서 컴파일 옵션중 any를 명확히 써줘야 하는데 그렇지 않으면 오류를 뱉도록 하는 옵션인 noImplicitAny 라는 옵션이 있음 (strict 옵션에 포함되서 켜짐)
  • any는 계속해서 개체를 통해 전파 됨 (편의는 타입 안전성을 잃는 대가로 오는 것임)
const returnAny = (message: any): any => {
  console.log(message);
};

const any1 = returnAny("아무거나");

any1.toString(); // toString도 any가 됨

let looselyTyped: any = {};

const d1 = looselyTyped.a.b.c.d.e; // 계속해서 any로 아무거나 올수 있게 됨

const leakingAny = (obj5: any) => {
  const a5: number = obj5.num;
  // number로 제한을 해줘야 나중에 맞지 않는 함수인지 check 할수 있음 (number 명시 안하면 any로 전파되서 적절한 함수의 사용이 되었는지 check를 못함)
  const b5 = a5 + 1;
  return b5;
};

const c5 = leakingAny({ num: 0 }); // c5는 any가 됨
// c5.indexOf(0) // number는 indexOf가 없으므로 오류로 잡힘

unknown

  • 응용 프로그램을 작성할 때 모르는 변수의 타입을 묘사해야하는 경우
  • type적으로 누수를 줄이기 위해서
  • 동적 콘텐츠로 부터 오기도 함 (사용자로부터, 또는 API의 모든 값을 의도적으로 수락하기를 원할 수 있음)
  • 컴파일러와 미래의 코드를 읽는 사람에게 이 변수가 무엇이든 될 수 있음을 알려주고 싶을 때
  • unknown의 경우 무조건 한정 되어야 사용할 수 있음 (바로 직접적으로 할당 불가함)
  • any 보다 type safe함
  • 컴파일러가 타입을 추론할 수 있게끔 타입의 유형을 좁히거나, 타입을 확정안해주면 다른곳에 할당 할 수 없고, 사용 불가함
  • runtime error를 줄일 수 있음
  • any 대신 unknown을 사용하도록 하여야 함
declare const maybe: unknown;

const aNumber: number = maybe // Error 바로 할당 불가

Type Guard

  • runtime 때 타입을 한정 시킴
if (maybe === true) {
  // if를 통해서 추론할 수 있게 타입 유형을 좁혀줌
  const aBoolean: boolean = maybe; // 앞의 조건에 맞게 알아서 값을 maybe에 유추해서 넣어줌 (number)

  const atring: string = maybe; // Error
}

if (typeof maybe === "string") {
  const atring: string = maybe; // 앞의 조건에 맞게 알아서 값을 maybe에 유추해서 넣어줌 (string)

  const aBoolean: boolean = maybe; // Error
}

never

  • return에 사용되는 type
  • 어떠한 형태도 return 되지 않거나, 항상 오류를 출력함을 의미 (무한 루프)
  • never 타입은 모든 타입의 subtype이며, 모든 타입에 할당 할수 있음
  • 하지만 , never에는 그 어떤 것도 할당 할 수 없음 (any도 불가능 함)
  • 잘못된 타입을 넣는 실수를 막고자 할 때 사용하기도 함
  • 함수의 바디 부분이 끝나지 않아야 함
const error = (message: string): never => {
    throw new Error(message);
};

const fail = () => {
    return error('failed');
};

const infiniteLoop = (): never => {
    while (true) {}
};

let a6: string = 'hello';
declare const b6: string | number;

if (typeof a6 !== 'string') {
    a6; // string인데 string이 아닌 경우니까 never로 간주됨
}

if (typeof b6 !== 'string') {
    b6; // 나머지인 number가 나옴
}

void

  • return type으로서 사용됨
  • return 값이 없으므로 어떻게 활용하지 않겠다를 명시적으로 표현하고 막는 행위라고 볼 수 있음
  • undefined 만 return 값 (void)으로 할당 가능함
const returnVoid = (message: string) => {
  console.log(message);

  return undefined;
  // return; 이어도 상관 X, return이 없어도 상관x
};

const r = returnVoid("no return"); // X (잘못된 사용)
returnVoid("no return"); // O  (이게 잘 사용한 것임)