[노마드TS] day 2

·2023년 3월 7일
0

TypeScript공부중

목록 보기
3/6

#2.2 Types of TS part One

ts 타입에 대해 알아보자.

예를 먼저 들자.

// 오류 발생 코드
const player:{
  name:string,
  age:number
}={
  name:'coco'
};

일 때, ts에서는 오류를 내뱉는다. 이유는, nameage를 받는다고 했는데, 실제로는 name하나만 있기 때문이다.
age가 꼭 필수가 아닌 경우에는 어떻게 하냐면

//...
age?:number

라고 수정하면 ts오류가 뜨지 않는다.
이것이 optional parmeter(선택적 변수)를 지정하는 방법이다.

// 수정된 코드
const player:{
  name:string,
  age?:number
}={
  name:'coco'
};

이제 if문으로 age가 10이상일 때 실행하게 될 코드를 적어보자.

// 오류 발생 코드
if(player.age < 10){}

위 코드에서 ts오류가 나타난다. 왜냐하면 age가 필수 입력값이 아니기때문에 age의 타입이 number또는 undefined가 들어올 수 있기 때문이다.

그래서 player.age가 있고, 있다면 실행하게끔 수정을 해야한다. &&연산자를 사용한다.

// 수정된 코드
if(player.age && player.age < 10){}

자, 그렇다면 무수히 많은 player가 있다고 가정해보자.
그러면 코드를 이렇게 작성하게 될 것이다.

const playerJin:{
  name:string,
  age?:number
}={
  name:'jinjin'
};

const playerSol:{
	name:string,
  	age?:number
}={
  name:'solsol',
  age: 2
};

.
.  
.

위의 코드를 보면 어떠한가? 중복된 타입 지정이 거슬리지 않는가??
그렇다. 위의 코드는 중복된 코드를 Alias(별칭)타입을 생성해서 따로 뺄 수 있다.

코드를 수정해보자

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

const playerJin:Player={
  name:'jinjin'
};

const playerSol:Player={
  name:'solsol',
  age: 2
};

코드가 한 결 간결하지고 깔끔해졌다.
타입별칭을 사용할 때는 항상 type으로 선언을 하고 선언명의 첫문자는 꼭 대문자여야 한다.

여기서 더 나아가면, Player라는 별칭을 타입으로 사용하여jinsol모두 player라는걸 알 수 있기때문에 playerJinjin으로, playerSolsol로 변수이름을 수정할 수 있다.

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

const jin:Player={
  name:'jinjin'
};

const sol:Player={
  name:'solsol',
  age: 2
};

여기서 Alias는 object만 가능한것이 아닌 여러 타입이 가능하다.

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

하지만 위 처럼 과도하게 재사용하는 것은 좋지 않은 방법이다.
코드가 깔끔하고 명확해질 때까지만 이 작업을 하면 된다.


이번엔 함수의 return값의 타입을 지정하는 방법을 배워보자.
조건: 이 함수는 player의 object를 만들고 그 결과로 player를 반환한다.

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

function playerMaker(name:string){
  return{
    name // name:name 과 동일하다. key value가 똑같은 이름이면 하나만 써도 됨.
  }
}

위의 코드에서 ts는 우리가 object를 return하는 것만 알고있다. 타입이string인 name이 들어있는 object를 말이다.
하지만 우리는 ts에게 playerMaker는 Player타입을 return하고 있다고 알려주고싶다.

const coco = playerMaker('kko'); // 인자에 아무것도 들어있지 않으면(===playerMaker()) 오류를 발생시킴.
coco.age = 2;

위의 코드에서 playerMaker에는 name만 있는 object를 반환하기 때문에 coco.age를 찾을 수 없어서 오류를 일으킨다.
하지만 우리는 위에서 말했듯이 Player타입을 return하고 있다고 알려주고싶다.

방법은 간단하다. 함수 뒤에 타입을 명시하면 된다.

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

function playerMaker(name:string):Player{
  return{
    name // name:name 과 동일하다. key value가 똑같은 이름이면 하나만 써도 됨.
  }
}

const coco = playerMaker('kko');
coco.age = 2;

playerMaker함수에서 인자를 받는 괄호 옆에 콜론:을 쓰고 리턴타입을 명시해주면 된다.
그러면 더이상 coco.age에서 오류가 생기지 않는다.

ES6문법인 화살표함수로 바꾸어보자

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

const playerMaker = (name:string) : Player => ({name});
const coco = playerMaker('kko');
coco.age = 2;

#2.3 Types of TS part Two

js에서는 없는 readonly 동작이 ts에서는 가능하다.
위의 코드를 예로 들어보자

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

const playerMaker = (name:string) : Player => ({name});
const coco = playerMaker('kko');
coco.age = 2;
coco.name = 'koko'

Player 타입에서 name속성을 readonly로 바꾸었다. 'readonly'를 앞에 추가하면 읽기전용이 되어 수정이 불가하다.
그러므로 coco.name = 'koko'로 수정할 때 ts는 오류를 발생시켜준다.

readonly를 다른곳에서도 활용할 수 있다.

const numbersArr : readonly number[] = [1,2,3,4];
numbersArr.push(5);

위 코드처럼 numberArr변수의 타입을 readonly로 정하면 .push할 때 ts에서 'push라는 것이 readonly number[]타입에 존재하지 않기' 때문에 오류를 발생시킨다.
readonly를 지우면 .push가 잘 동작한다.

배열을 바꾸지 않는 .map이나 .filter는 readonly가 붙어도 사용할 수 있다.


이번엔 Tuple에 대해 배워보자. tuple도 ts에만 있다.

Tuple은 array를 생성할 수 있게 한다. 최소한의 길이를 가져야하고, 특정 위치에 특정 타입이 있어야한다.

예를 들어보자

const player : [string, number, boolean] = ['coco',2,true];

player변수는 ts에게 이 array가 최소 3개의 아이템을 가지며, string,number,boolean순서대로여야 한다는 것을 알릴 수 있다.

Tuple은 항상 정해진 개수의 요소를 가져야하는 array를 지정할 수 있다는 것이 중요하다.

튜플로 타입 선언된 변수를 수정할 때 잘못되었다면 바로 알 수 있다.

const player : [string, number, boolean] = ['coco',2,true];
player[0] = 1; // 오류 발생. 0번째 배열은 항상 string인데 number로 바꿀 수 없다.

readonly와 함께 쓰면 올바른 수정이라 할지라도 수정이 불가능하게 할 수 있다.

const player : readonly [string, number, boolean] = ['coco',2,true];
player[0] = 'koko';

any 타입은 타입을 지정하지 않는다면 기본적으로 타입추론에 의해 any가 들어가게 된다.

const aa = []; // 여기서 aa의 타입은 any[]로 되어있다.

any는 쉽게말해서 ts에서 벗어나 js가 되고싶을때나 ts에게 바보같은 짓을 하고싶다고 허락받고 싶을 때 사용한다.
any는 ts의 모든 보호장치를 비활성화 시킨다.
무분별한 any는 ts를 활용하지 못하고 있는 것이다. 지양해야한다.

#2.4 Types of TS part Three

unknown
어떤 타입인지 모르는 변수는 ts에게 어떻게 말해줘야할까? 이럴 때 unknown을 사용하면 된다.

let a: unknown;

a변수의 타입을 unknown으로 해두면, 어떤 작업을 할려면 a변수의 타입을 먼저 확인하는 방식으로 할 수 있다.
예를 들어서

let a: unknown;

let b = a + 1;

변수 b를 선언하여 a변수에 1을 더한다고 하면 ts는 오류를 발생시킨다.
왜냐하면 a는 unknowm이기 때문에 number인 1을 더할 수 없기 때문이다
이럴때는 위에서 말한것처럼 a변수의 타입을 먼저 확인하는 방식으로 해야한다.

let a: unknown;

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

이렇게 typeof를 사용하여 a변수의 타입이 number인지 먼저 확인한 후에 맞다면 조건문 안의 코드를 수행하게 된다.

또는

let a: unknown;

if(typeof a === 'number'){
  let b = a + 1;
};
a.toUpperCase();

변수 a를 upperCase(===대문자) 하고싶지만 a는 unknown이기 때문에 못한다.
이럴때에도 a변수 타입을 먼저 확인하는 방식으로 해야한다.

let a: unknown;

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

if(typeof a === 'string'){
  a.toUpperCase();
};

이러면 에러없이 잘 동작한다.


void
void는 아무것도 return하지 않는 함수를 대상으로 사용한다.

// void발생 함수
function hello(){
  console.log('hi');
}

일 때, 함수 hello타입은 void로 되어 있는걸 확인할 수 있다.

void는 따로 지정할 필요가 없다. ts는 함수가 아무것도 return하지 않는다는것을 자동으로 인식한다.


never
never타입은 많이 사용하진 않지만 무엇인지 아는 것은 중요하다.
never는 함수가 절대 return하지 않을 때 발생한다.

function hello():never{
  return 'x';
}

일 때 return문에 에러가 발생한다.

하지만 return문에 오류를 발생시키면 오류가 나지 않는다.

// 여기서의 hello함수는 return하지 않고 오류를 발생시키는 함수임.
function hello():never{
  throw new Error('x');
}

또한 nenve는 타입이 두가지 일수도 있는 상황에 발생할 수 있다.

function hello(name:string|number){
  if(typeof name === 'string'){
    name // 여기서의 name 타입은 string이다.
  } else if(typeof name === 'number){ 
    name // 여기서의 name 타입은 number이다.
  } else {
    name // 여기서의 name 타입은 never이다.
  }
}
profile
어두운 밤하늘, 밝은 달빛.

0개의 댓글