이론 (Front-end)/TypeScript

[TypeScript] 타입 시스템

이우열 2023. 7. 5. 02:31
728x90

✅ 타입스크립트의 타입 체커(Type Checker)와 소통하는 방법

let a = "hello"
let b: boolean = false;
let c: number[] = []

a는 string이라고 추론할 수 있도록 하는 방법입니다.

b는 boolean이라고 명시적으로 알려주는 방법입니다.

c는 숫자만 들어갈 수 있는 array라고 명시적으로 선언하는 방법입니다.

 

 

 

 

const player: object = {
    name: "nico",
};

player.name;

객체의 경우도 object라고 명시적으로 선언할 수 있지만 이 때는 오류가 발생합니다.

 

object라는 타입에 name이라는 속성이 없기 때문입니다.

 

 

const player: {
    name: string
} = {
    name: "nico"
};

player.name;

위의 오류를 해결하기 위해 object 대신 중괄호를 사용하여 객체 안의 타입을 명시해줍니다.

 

 

 

코드가 간결해져 가독성이 올라가기 때문에 가능하면 타입스크립트가 추론하게 하는 것이 좋습니다.

하지만 명시적으로 선언해주어야 할 경우가 있는데 이는 array 안의 값이 없을 경우 등 타입을 지정해야 할 때가 있습니다.

 


 

✅ optional type(선택적 타입)

만약 객체 안에 타입을 지정할 경우 어떤 객체는 원하는 값을 가지고 있지 않는 경우가 있습니다.

player라는 객체는 name이라는 값은 무조건 가지고 있지만 age는 가지고 있을 수도 있고 가지고 있지 않을 수도 있는 경우입니다.

 

const player: {
    name: string,
    age?: number
} = {
    name: "nico"
};

위와 같이 player를 선언할 때 name과 age를 갖는 타입으로 선언했지만 age는 선택적으로 만들기 위해서

?를 붙여 선택사항으로 만들 수 있습니다.

 

 

이와 같이 객체의 타입을 명시했다면 객체의 요소를 사용할 때 문제가 발생합니다.

객체의 요소 중 선택사항인 요소를 사용하려면 먼저 요소의 존재 여부를 판단해야 합니다.

const player: {
    name: string,
    age?: number
} = {
    name: "nico"
};

if (player.age && player.age < 10) {
    // ...
};

위와 같이 player의 age를 사용한다면 age가 있는지 조건문을 통해 걸러서 사용합니다.

 


 

✅ Alias(별칭) 타입 사용

const playerNico: {
    name: string,
    age?: number
} = {
    name: "nico"
}

const playerLynn: {
    name: string,
    age?: number
} = {
    name: "lynn",
    age: 12
}

이처럼 많은 player를 만들 경우 같은 코드가 반복됩니다.

 

 

이 때는 자신만의 별칭 타입을 만들어 코드를 재사용할 수 있습니다.

type Player = {
    name: string,
    age?: number
};

const nico: Player = {
    name: "nico"
};

const lynn: Player = {
    name: "lynn",
    age: 12
};

Player라는 별칭 타입을 만들고 생성하는 객체의 타입에 지정하여 코드를 재사용할 수 있도록 하고 간결하게 해줍니다.

 

 

type Age = number;
type Player = {
    name: string,
    age?: Age
};

Age라는 별칭 타입과 같이 객체가 아닌 타입도 별칭으로 사용 가능하지만 굳이 사용할 필요는 없습니다.

즉, 코드가 간결해질 때까지만 별칭을 사용하는 것이 바람직합니다.

 


 

✅ 함수의 return 타입 지정

type Player = {
    name: string,
    age?: number
};

function playerMaker(name: string) {
    return {
        name: name
        // name
    }
}

const nico = playerMaker("nico");
nico.age = 12; // 에러 발생, age 요소가 없기 때문

이 코드는 playerMaker라는 함수를 통해 string 타입의 인자를 받아 객체로 return하여 객체를 생성합니다.

 

 

하지만 우리는 생성한 객체의 타입을 Player 타입으로 만들고 age 요소를 다룰 수 있게 하고 싶습니다.

 

 

type Player = {
    name: string,
    age?: number
};

function playerMaker(name: string): Player {
    return {
        name: name
        // name
    }
}

const nico = playerMaker("nico");
nico.age = 12;

 

함수의 괄호 뒤에 타입을 명시해주면 return 타입을 지정할 수 있어

해당 타입의 요소에 접근할 수 있습니다.

 

 

✏️ 화살표 함수 사용

type Player = {
    name: string,
    age?: number
};

const PlayerMaker = (name: string): Player => ({ name });

화살표 함수를 사용하고자 한다면 위와 같이 사용할 수 있습니다.

 


 

✅ readonly(읽기 전용) 속성

객체 타입의 요소를 읽기 전용으로 만들어 수정이 불가능하게 하고 싶다면 readonly를 변수명 앞에 붙이면 됩니다.

 

type Player = {
    readonly name: string,
    age?: number
};

const PlayerMaker = (name: string): Player => ({ name });

const nico = playerMaker("nico");
nico.age = 12;
nico.name = "las"; // 에러 발생

name이라는 요소가 readonly로 선언되었기 때문에 객체를 만들고 name이라는 요소에 접근해 값을 변경할 수 없습니다.

 

 

const numbers: readonly number[] = [1, 2, 3, 4];
numbers.push(1); // 에러 발생

readonly number[] 타입에 push라는 것이 존재하지 않기 때문에 push 함수를 사용할 수 없습니다.

 

readonly로 선언된 array는 map이나 filter와 같은 함수는 사용할 수 있습니다.

즉, 불변성을 가지지만 값을 변하게 하지 않는 함수는 활용 가능합니다.

 


 

✅ Tuple(튜플)

Array를 생성할 수 있게 해주는데 최소한의 길이를 가져야 하고 특정 위치에 특정 타입이 있어야 함
const player: [string, number, boolean] = []; // 에러 발생

const player: [string, number, boolean] = ["nico", 1, false];

3개의 요소가 필요하고 순서대로 지정된 타입을 가져야 한다고 선언할 경우 사용합니다.

 

빈 배열로 선언할 경우 에러가 발생합니다.

 


 

✅ undefined, null

undefinednull은 다른 타입과 같이 그대로 사용할 수 있습니다.

let a: undefined = undefined;
let b: null = null;

type Player = {
    age?: number
};

optional type으로 명시할 경우 있거나 없다가 되므로 number가 되거나 undefined가 될 수 있다고 알려줍니다.

 


 

✅ any

타입스크립트의 보호장치로부터 빠져나오고 싶을 때 사용하는 타입
사용하지 않는 것이 좋고, 사용한다면 신중하게 사용해야 함
const a: any[] = [1, 2, 3];
const b: any = true;

a + b;

원래의 타입스크립트라면 array와 boolean의 합 연산이므로 에러가 발생해야 하지만

any 타입을 사용해 에러가 발생하지 않습니다.

 


✅ unknown

만약 API를 요청했을 때와 같이, 응답의 타입을 모른다면 unknown을 사용할 수 있음
let a: unknown;

let b = a + 1; // 에러 발생, a의 타입을 모르기 때문

if (typeof a === "number") {
    let b = a + 1;
}

if (typeof a === "string") {
    let b = a.toUpperCase();
}

unknown 변수를 사용하기 위해서는 타입을 알아야 합니다.

타입스크립트가 강제로 타입을 확인시켜 에러를 방지합니다.

 


 

✅ void

아무 것도 return 하지 않는 함수에 사용
function hello() {
    console.log("x");
};

 

void의 경우는 따로 지정해줄 필요가 없습니다.

 


 

✅ never

함수가 절대 return 하지 않을 때 사용
예를 들어 함수에서 exception(예외)이 발생할 때
function hello(): never {
    return "X"; // 에러 발생
}

never 타입을 붙이면 return이 있는 경우 에러가 발생합니다.

 

 

function hello(): never {
    throw new Error("xxx");
}

위의 함수는 return 하지 않고 오류를 발생시키는 함수입니다.

 

 

function hello(name: string|number) {
    if (typeof name === "string") {
        name // name: string
    } else if (typeof name === "number") {
        name // name: number
    } else {
        name // name: never
    }
}

never타입이 두가지일 수도 있는 경우에 발생할 수도 있습니다.

 

name이라는 매개변수는 타입이 string일 수도 있고 number일 수도 있습니다.

 

조건에 따라 string일 경우와 number일 경우를 나눠준다면

나머지 경우는 절대 접근할 수 없기 때문에 never 타입이 붙습니다.

728x90

'이론 (Front-end) > TypeScript' 카테고리의 다른 글

[TypeScript] Interface(인터페이스)  (0) 2023.12.27
[TypeScript] Static 키워드  (0) 2023.12.27
[TypeScript] 타입 확장  (1) 2023.12.23
[TypeScript] Class(클래스)  (1) 2023.12.23
[TypeScript] 함수  (1) 2023.12.22