1편. 나는 타입스크립트를 제대로 사용하고 있을까?

Jo yun hee·2023년 7월 10일
0
post-thumbnail
post-custom-banner

(지난 날.. 나의 코드는 any 범벅...)

인프런 한 입 크기로 잘라먹는 타입스크립트 강의를 기반으로 정리했습니다. 보시다가 잘못된 정보를 발견하신다면 댓글을 남겨주시면 감사하겠습니다 :)

1. 타입스크립트 개론

1-1. 타입스크립트를 소개합니다.

새롭게 배우고 싶거나 배울 필요성을 느끼는 프로그래밍 언어를 한 가지 골라주세요. 라는 프로그래머스 사이트 질문에서 프론트엔드 직무는 1위로 타입스크립트를 뽑았습니다. 이 설문조사만 봐도 타입스크립트는 압도적인 인기를 얻고 있습니다.

이렇게 인기가 많은 타입스크립트를 한 마디로 정의하자면...!

타입스크립트란?
타입스크립트는 자바스크립트의 확장판입니다.

1-2. 개발자들은 왜 타입스크립트에 열광하게 되었을까요?

자바스크립트는 자유로운 문법을 가지고 있어 프로그래머가 쉽고 빠르게 코드를 작성할 수 있는 장점이 있습니다. 그러나 이러한 자유로움은 버그의 발생 가능성을 높여 매우 취약한 측면을 가지고 있습니다. 또한, 자바스크립트는 웹 브라우저에서만 동작한다는 한계점을 가지고 있습니다.

이 때, Node.js가 등장하게 되었습니다. Node.js는 JavaScript 런타임 환경으로, JavaScript로 서버를 개발하거나 어플리케이션을 만들 수 있게 해줍니다. 이로 인해 자바스크립트는 더욱 큰 인기를 얻게 되었습니다.

하지만, 자바스크립트는 엄격하지 못하고 자유로운 특성을 가지고 있어 복잡한 대규모 어플리케이션에서 프로그램의 안전성을 떨어뜨릴 수 있습니다. 이를 보완하기 위해 타입스크립트가 등장하였습니다. 타입스크립트는 대규모 프로젝트에서 안전장치로써 타입을 추가하여 개발을 안정적으로 할 수 있는 도구입니다.

방금 말한 프로그램의 안전성의 예시를 들어보도록 하겠습니다.

let a = "hello" //문자열
a= 19980505 //숫자

a.toUpperCase(); 

위 코드를 실행하면 오류가 발생합니다. toUpperCase()는 문자열에만 적용할 수 있는 메서드이지만, 위의 코드에서는 숫자에 적용하려고 시도하고 있습니다. 따라서 오류가 발생하는 것은 당연합니다.

이러한 상황에서 우리는 신중하게 고려해야 할 문제를 직면하게 됩니다. 코드가 실행되고 나서 오류가 발생한다는 점입니다. 실행 중에 오류가 발생하면 심각한 문제가 될 수 있기 때문에 주의해야 합니다.

타입스크립트와 같은 언어는 이를 미리 방지하기 위해 실행 전에 타입 체크를 수행하여 오류를 방지합니다. 프로그램이 실행되기 전에 타입 오류를 발견할 수 있어 매우 유용합니다. 이를 통해 프로그램의 안정성을 높일 수 있습니다.

1-3. 타입스크립트는 어떻게 동작할까요?

타입스크립트 코드는 AST로 변환하고 타입을 검사한 후 타입에 오류가 있다면 컴파일이 중단됩니다. 타입검사를 통과하면 자바스크립트코드로 변환되고 AST변환과 바이트코드 변환을 거쳐 실행이 됩니다. (대부분 프로그래밍 언어는 AST로 변환하고 AST를 다시 바이트 코드로 변환후 실행됩니다.)

2. 타입스크립트 기본

2-1. 기본타입

타입스크립트가 내장하고 있는 다양한 기본타입이 있습니다.

2-2. 원시타입과 리터럴 타입

원시타입은 하나의 값만 저장하는 타입입니다.

//1.number
let num1: number = 123;
let num1: number = -123;
let num1: number = 0.123;
let num1: number = -0.123;
let num1: number = Infinity;
let num1: number = -Infinity;
let num1: number = NaN;

//number 타입에러
num1.toUpperCase() //숫자타입에 문자와 관련된 메서드는 사용할 수 없다. 

//2.string타입 
let str1: string = "hello";
let str1: string = `hello`;
let str1: string = 'hello';
let str1: string = `hello ${num1}`;

//string 타입에러
str1.toFixed() //문자타입에 숫자와 관련된 메서드는 사용할 수 없다. 

//3.boolean
let bool1: boolean = true;
let bol2: boolean = false;

//4.null
let null1: null = null;

//5.undefined
let unde1: undefined = undefined;

리터럴 타입은 값을 나타내는 타입입니다.

let numA: 10 = 10;
numA = 12; //10이 아닌 다른 숫자를 넣으면 타입에러!!

2-3. 배열과 튜플

배열타입은 배열을 저장하는 변수의 이름 뒤에 타입 주석의 시작을 의미하는 콜론(:)을 작성한 다음 배열요소타입[] 형식으로 배열 타입을 정의합니다.

let numArr: number[] = [1, 2, 3];
let strArr: Array<boolean> = [true, false, true];


//배열에 들어가는 요소들의 타입이 다양할 경우 
let multiArr: (number | string)[] = [1, "hello"];

//다차원 배열의 타입을 정의하는 방법 
let doubleAr: number[][] = [
	[1, 2, 3],
  [4, 5],
];

튜플타입은 자바스크립트에는 없는 타입스크립트의 특수한 타입으로 길이와 타입이 고정된 배열을 의미합니다.

let tup1: [number, number] = [1, 2];
let tup2: [number, string, boolean] = [1, "2", 3]; //타입에러!!!

튜플 언제 사용하나요?
회원정보를 2차원 배열로 저장하기로 했습니다. 각 배열의 0번 인덱스에는 회원이름을 저장해두고 1번 인덱스에는 회원의 나이를 저장해 두었을 때, 누군가 순서를 잘 못 배치하면 문제가 일어날수 있습니다. 이러한 문제를 방지할때 튜플을 사용합니다.

const users = [
  ["메리", 20],
  ["이아무개", 25],
  ["김아무개", 30],
  ["박아무개", 40],
  [22, "조아무개"], // <- 새로 추가함 
];

//통일성이 무너짐...이럴때 튜플타입 추가!!
 const users:[string, number][] = [
  ["메리", 20],
  ["이아무개", 25],
  ["김아무개", 30],
  ["박아무개", 40],
  [22, "조아무개"], // <- 타입 에러!!! 
];

2-4. 객체

객체 리터럴타입은 객체에 모든 프로퍼티들 타입까지 정의하여 사용해야 합니다.

let user: object = {
	id: 1,
	name: "메리",
}
user.id; //타입에러!!! 자바나 c언어에서는 객체 타입을 object라고 명시를 하면 끝이지만..타입스크립트는 에러발생!!


let user: {
	id: number;
	name: string;
} = {
	id: 1,
	name: "메리",
}

user.id; // 모든 프로퍼티들 타입까지 정의해줘야 합니다. 

특수한 프로퍼티 정의하기

선택적 프로퍼티 : 있어도 되고 없어도 되는 프로퍼티의 이름 뒤에 ?룰 붙여줍니다.

let user: {
  id?: number; // 선택적 프로퍼티가 된 id
  name: string;
} = {
  id: 1,
  name: "메리",
};

user = {
  name: "홍길동",
};

읽기전용 프로퍼티 : 특정 프로퍼티에 readonly 키워드를 붙여 읽기전용으로 만들 수 있다.

let user: {
  id?: number;
  readonly name: string; // name은 이제 Readonly 프로퍼티가 되었음
} = {
  id: 1,
  name: "메리",
};

user.name = "dskfd"; // 오류 발생

2-5. 타입 별칭과 인덱스 시그니처

터입별칭? 타입을 변수처럼 정의하여 사용할 수 있습니다.


//타입중복 코드 발생 예시 코드
let user: {
  id: number,
  name: string,
  nickname: string,
  birth: string,
  bio: string,
  location: string,
} = {
  id: 1,
  name: "메리",
  nickname: "winterlood",
  birth: "1997.01.07",
  bio: "안녕하세요",
  location: "부천시",
};

let user2: {
  id: number,
  name: string,
  nickname: string,
  birth: string,
  bio: string,
  location: string,
} = {
  id: 1,
  name: "메리",
  nickname: "winterlood",
  birth: "1997.01.07",
  bio: "안녕하세요",
  location: "부천시",
};
  
//타입 중복코드를 제거하기 위해 타입별칭을 사용한다. 
type User = {
  id: number,
  name: string,
  nickname: string,
  birth: string,
  bio: string,
  location: string,
}
let user: User = {
  id: 1,
  name: "메리",
  nickname: "merry",
  birth: "1997.01.07",
  bio: "안녕하세요",
  location: "부천시",
};

let user2: User = {
  id: 1,
  name: "메리",
  nickname: "merry",
  birth: "1997.01.07",
  bio: "안녕하세요",
  location: "부천시",
};
  
  
//타입별칭 같은 스코프내 사용시 에러 발생 
type User = {
  id: number,
  name: string,
  nickname: string,
  birth: string,
  bio: string,
  location: string,
}

type User = {
  id: number,
  name: string,
  nickname: string,
  birth: string,
  bio: string,
  location: string,
}   //error  
  
  
function func() {
	type User = {};
} //다른 스코프에 있기 때문에 괜춘! 

인덱스 시그니처? key와 value 규칙에 맞게 타입 정하기

type CountryCodes = {
	[key: string]: string;
} 

let countryCodes: CountryCodes = {
	Korea: "ko",
	UnitesState: "us",
	UnitedKingdom: "uk",
}

2-6. Enum 타입

Enum타입은 여러가지 값들에 각각 이름을 부여해 열거하여 사용하는 타입입니다.

enum Role {
	ADMIN = 0, //만약 별도의 값이 설정되지 않은 경우 기본적으로 0부터 시작합니다.
	USER = 1,
	GUEST = 2,
}

enum Language {
	korean = "ko",
	english = "en",
}

const user1 = {
	name: "메리",
	role: Role.USER ,
	language: Language.korean,
}

const user2 = {
	name: "홍길동",
	role: Role.ADMIN,
	language: Language.english, //컴파일 되고 나서  enum이 자바스크립트 객체로 변환된다.
}

const user2 = {
	name: "홍길동",
	role: Role.GUEST,
}

2-7. Any와 Unknown 타입

any 타입은 특정 변수의 타입을 확실히 모를때 사용합니다. any를 쓴다고 하면 타입스크립트를 사용하지 않겠다는 이야기입니다... 사용을 피합시다. 또한 any는 런타임때 에러를 일으킵니다.


let anyVar = 10;
anyVar = "hello"; //타입 error 발생. 타입스크립트는 초기화하는 값으로 변수에 타입을 자동 추혼합니다. 지금 숫자타입 10으로 추론되고 있기 때문에 문자열이 들어갈 수 없습니다. 

//하지만 any를 사용하면 가능합니다. 무서운 아이입니다.
let anyVar: any = 10;
anyVar = "hello";

anyVar = true;
anyVar = {};
anyVar = () => {}; //함수를 넣음. 

anyVar.toUpperCase(); //함수에서 toUpperCase()를 사용할수가 없다. 근데 이 에러가 런타임에서 발생함. 결국 any를 쓴다는것은 타입스크립트 쓰지 않겠다는 이야기...>!! 
anyVar.toFixed();
anyVar.a;

unknown타입은 any와 비슷하지만 any보다 더 안전한 타입입니다. any 타입을 써야한다면 unknown타입을 사용하세요!

let num: number = 10;
let unknownVar: unknown;

unknownVar = "";
unknownVar = 1;
unknownVar = () => {};
//any처럼 모든 타입을 넣을 수 있지만 ...!
num = unknownVar; //num이라는 숫자타입 변수에 unknown타입을 할당 할 수 없습니다. (any는 가능)
unknownVar.toUpperCase(); //절대 허용이 안됩니다.(any는 가능)

2-8. Void와 Never 타입

void타입은 아무런 값도 반환하지 않는 함수의 반환값 타입을 정의할 때 사용합니다.

function func2(): void {
  console.log("hello");
}

never타입은 함수가 어떠한 값도 반환할 수 없는 상황일 때 사용합니다.

//무한루프를 돌기 때문에 아무런 값도 반환할 수 없습니다.
function func3(): never {
  while (true) {}
}
post-custom-banner

0개의 댓글