[TypeScript] TypeScript 기본&기본타입

HIHI JIN·2023년 2월 27일
0

typescript

목록 보기
2/10
post-thumbnail

타입스크립트 핸드북Udemy강의를 토대로 Typescript를 공부합니다.

Using types

자바스크립트와 타입스크립트가 가진 타입의 공통점
number type : 숫자형은 단 하나뿐, 정수형과 실수형 모두 숫자형
string type : 작은 따옴표, 큰 따옴표, 백틱(`)과 같은 세 가지 방법 중 하나로 정의
(백틱은 일부 데이터를 동적으로 주입할 수 있는 일반 문자열, 즉, 템플릿 리터럴을 작성가능)
불리언 타입 : 참(true)이나 거짓(false)

자바스크립트와 타입스크립트가 가진 타입의 차이점
자바스크립트도 몇가지 데이터 타입을 가지지만 타입스크립트는 더 많은 타입을 가진다.
타입스크립트는 자신만의 타입을 작성할 수 있게 해준다.

브라우저에는 내장 타입스크립트 지원이 없기 때문에 런타임에서 자바스크립트가 다른 식으로 작동하도록 변경하지 않습니다.

기본적으로 타입스크립트는 컴파일을 차단하지 않고 이 실수에 대해 알려주며 지적합니다.

이런 실수를 방지하기 위해 수정할 수 있도록 app.js와 app.ts가 동시에 열려 있지 않은지 확인하기!
이 문제를 수정하는 자바스크립트 파일을 닫는 중복 함수 구현과 관련된 IDE에서 에러가 발생할 수 있기 때문입니다.

자바스크립트는 동적 타입!
나중에 문자열을 할당할 때 처음에 숫자형을 잡아둘 수 있는 변수가 있더라도 전혀 문제 없다는 것을 의미합니다.
그래서 특정 타입에 의존하는 코드가 있는 경우, 런타임에서 무언가의 현재의 타입을 확인할 수 있게 해주는 typeof 연산자를 사용하는 거죠.

타입스크립트는 정적 타입
개발 도중에 끝나는 변수와 매개변수의 타입을 정의한다는 것을 의미합니다.
런타임 중에 갑자기 변경되지는 않습니다.
타입스크립트는 자바스크립트로 컴파일 되기 때문에 이론적으로는 그럴 수 있지만
타입스크립트를 사용하여 갑자기 새로운 유형의 데이터를 변수,
예를 들어, 우리가 앞서 숫자형이어야 한다고 설정했던 변수에 할당하는 코드를 작성하고
문자열을 할당하면 개발 도중에 에러가 발생하므로 어떤 타입을 보유할 수 있는지 여부를 명확히 할 수 밖에 없습니다.

따라서 런타임 검사는 타입스크립트로 수행할 수 있는 것만큼 유연하거나 강력하지 않습니다.
이따금 런타임에서 타입을 가져오는 것이 유용할 수 있겠지만,
개발 도중에 가져오는 것이 훨씬 나을 때도 있습니다.
알아두셔야 할 한 가지 중요한 점은 이런 타입스크립트 기능과 검사 기능이
자바스크립트 엔진에 내장되어 있지 않기 때문에 타입스크립트를 사용하면 개발 도중에만 지원을 받을 수 있다는 것입니다.
브라우저에서 실행할 수 없고, 그저 개발 도중 코드를 컴파일할 때만 실행할 수 있다.

타입스크립트의 다양한 핵심 타입

숫자형

function add(n1: number, n2: number, showResult: boolean, phrase: string) { //명시적 타입 할당
  // if (typeof n1 !== 'number' || typeof n2 !== 'number') {
  //   throw new Error('Incorrect input!');
  // }
  const result = n1 + n2;
  if (showResult) {
    console.log(phrase + result);
//phrase + n1 + n2 = 문자열+숫자이므로 수학적 계산이 되지 않고 문자열 연결만 된다.
// result = n1 + n2; 으로 먼저 수학적 계산을 끝낸 뒤 문자열과 계산결과를 더하더라도 수학적 계산결과는 남아있다.
  } else {
    return result;
  }
}
/
const number1 = 5; // 5.0
const number2 = 2.8;
const printResult = true;
const resultPhrase = 'Result is: ';
/
add(number1, number2, printResult, resultPhrase);

타입을 할당하는 방법

//number, string, boolean은 특별한 식별자, 타입스크립트로 추가된 특별한 구문
//타입스크립트 컴파일러는 이 코드를 자바스크립트 코드로 변환해주기에 유용한 컴파일러
function add(n1: number, n2: number, showResult: boolean, phrase: string) {
  // if (typeof n1 !== 'number' || typeof n2 !== 'number') {
  //   throw new Error('Incorrect input!');
  // }
  const result = n1 + n2;
  if (showResult) {
    console.log(phrase + result);
  } else {
    return result;
  }
}
/
const number1 = 5; // 5.0
const number2 = 2.8;
const printResult = true;
const resultPhrase = 'Result is: ';
add(number1, number2, printResult, resultPhrase);

타입스크립트는 추론된 타입이라 하더라도 추론된 타입을 망가뜨리면 에러를 출력한다.

function add(n1: number, n2: number, showResult: boolean, phrase: string) {
  // if (typeof n1 !== 'number' || typeof n2 !== 'number') {
  //   throw new Error('Incorrect input!');
  // }
  const result = n1 + n2;
  if (showResult) {
    console.log(phrase + result);
  } else {
    return result;
  }
}
let number1: string;
number1 = 5; //에러 발생
//타입스크립트는 추론된 타입이라 하더라도 추론된 타입을 망가뜨리면 에러를 출력한다.
const number2 = 2.8;
const printResult = true;
let resultPhrase = 'Result is: ';
resultPhrase = 0;
//타입 '0'은 문자열 타입에 지정할 수 없다는 에러 발생
//타입스크립트는 문자열을 저장하려는 것으로 추론했는데, 숫자형으로 저장하려고 시도 했기 때문에 에러발생
//타입스크립트는 이처럼 타입을 잘못 사용하고 있는지 확인하고 에러를 통해 알려주는 핵심 작업을 수행합니다.
add(number1, number2, printResult, resultPhrase);

퀴즈 - 타입 이해하기

“타입”이 바닐라 자바스크립트보다 유용하며 큰 이점을 제공하는 이유는 무엇인가요?
타입을 사용하면 오류를 미리 감지하고 일부 런타임 오류를 방지할 수 있다.

다음 코드는 컴파일 오류를 발생시키나요?

let userName: string;
userName = "Max";
userName = false;

Yes. string 타입이 할당된 변수에 불리언을 할당하는 것은 허용되지 않으며 컴파일 오류 발생

이 코드는 타입 추론에 의존하나요?

const age : number = 29;

No. 타입이 명시적으로 할당되었다.
타입스크립트는 명시적으로 타입을 할당할수도 있고, 타입을 추론할 수도 있어서 number 생략가능

자바스크립트 타입 (예. typeof 'Max' => 'string')과 타입스크립트 타입 (예. const name: string = '...')의 차이는 무엇인가요?
타입스크립트 타입은 컴파일 중에 확인되는 반면, 자바스크립트 타입은 런타임 중에 확인된다.

객체 형태

타입스크립트가 추론한 객체 타입
객체 타입은 객체와 거의 비슷하게 작성되는데,
키값 쌍을 작성하는 게 아니라 키 타입 쌍을 작성해야 한다.

// const person: {
//   name: string;
//   age: number;
// } 밑의 코드에 마우스 커서를 올리면 이 코드가 보인다.
const person = {
  name: 'Maximilian',
  age: 30
};
console.log(person.name);
//위 코드는 명시적 타입 할당, 아래는 타입 추론!
//보다 구체적인 객체 타입을 지정함으로써 추론된 모든 것을 자동으로 입력하도록 상세히 지정해야 한다.
//이는 새 자바스크립트 객체를 만드는 게 아니며 컴파일러 자바스크립트 코드에서 제거됩니다.
//이는 그저 특정 객체 타입의 타입스크립트 표기법으로 객체의 구조에 대한 정보를 제공하는 객체 타입의 역할을 합니다.
//빈 중괄호 쌍만 타입으로 할당하더라도 객체와 동일한 작업에 해당합니다.
//타입스크립트에 이것이 객체라고 알려주는 작업입니다.
//좀 더 구체적으로 키 타입을 명시한다.
//값의 타입이 키에 저장된다고 입력한다.
/
 const person: {
   name: string;
   age: number;
 } = {
//const person = {
  name: 'Maximilian',
  age: 30
};
console.log(person.name);
/
 //const person: {
 //  name: string;
 //  age: number;
 //} = {
const person = {
  name: 'Maximilian',
  age: 30
};
console.log(person.name);

중첩된 객체 및 타입

//물론 객체 타입은 중첩 객체에 대해서도 생성할 수 있습니다.
//다음과 같은 자바스크립트 객체가 있다고 가정해 봅시다:
const product = {
  id: 'abc1',
  price: 12.99,
  tags: ['great-offer', 'hot-and-new'],
  details: {
    title: 'Red Carpet',
    description: 'A great carpet - almost brand-new!'
  }
}
//이러한 객체의 타입은 아래와 같습니다.
{
  id: string;
  price: number;
  tags: string[];
  details: {
    title: string;
    description: string;
  }
}
//따라서 객체 타입 안에 객체 타입이 있다고 말할 수 있습니다.

배열 타입

타입스크립트에서는 배열에 무엇이든 지정 가능합니다.
배열의 타입을 유연하게도 제한적으로도 지정할 수 있습니다.

// const person: {
//   name: string;
//   age: number;
// } = {
const person = {
  name: 'Maximilian',
  age: 30,
  hobbies: ['Sports', 'Cooking']
};
let favoriteActivities: string[]; //문자열만 요소로 갖는 배열 타입이라고 명시적으로 타입 할당
favoriteActivities = ['Sports']; //문자열만 올 수 있고 숫자가 오면 에러 발생
console.log(person.name);
for (const hobby of person.hobbies) {\
//문자열만 요소로 갖는 배열이므로 hobby는 당연히 문자열 -> "타입추론"
//타입추론 : 타입을 명시적으로 할당하지 않았음에도 타입이 할당된 것처럼 보이는 것
  console.log(hobby.toUpperCase());
  // console.log(hobby.map()); // !!! ERROR !!!
}

튜플 타입

타입스크립트에는 바닐라 자바스크립트에서는 없던 몇 가지 새로운 개념과 타입이 추가되었는데, 그중 하나가 튜플!
튜플 : 길이, 타입이 고정된 배열, union(공용체) 타입
튜플은 항상 두개의 요소만 가져야 한다.
첫번째 요소는 항상 숫자 식별자, 두번째 요소는 항상 문자열 식별자
role: [number, string] 이 코드로 타입을 명시적으로 할당하면 이 배열은 튜플이 된다.

// const person: {
//   name: string;
//   age: number;
// } = {
const person: {
  name: string;
  age: number;
  hobbies: string[];
  role: [number, string];
} = {
  name: 'Maximilian',
  age: 30,
  hobbies: ['Sports', 'Cooking'],
  role: [2, 'author'] //마우스 커서를 대면 role: (string | number)[]
};
/
// person.role.push('admin');
//튜플 타입을 명시적으로 할당했더라도 이 코드는 정상작동 하는 이유는, push는 예외적으로 튜플에서 허용되므로
//타입스크립트에서 이런 에러를 걸러내지 못한다.
// person.role[1] = 10;
// role: [number, string];이코드가 없다면 위 코드는 에러가 발생하지 않는다.
// person.role = [0, 'admin', 'user'];
//튜플 타입을 명시했다면 이 코드는 에러가 난다. push를 쓰지 않는다면 길이는 고정된다.
/
let favoriteActivities: string[];
favoriteActivities = ['Sports'];
console.log(person.name);
for (const hobby of person.hobbies) {
  console.log(hobby.toUpperCase());
  // console.log(hobby.map()); // !!! ERROR !!!
}

열거형(enum)으로 작업하기

자바스크립트에는 없고 타입스크립트에만 존재하는 열거형을 생성하는 방법은,
식별자들을 중괄호 쌍 안에 넣는 방식으로, 열거 목록을 제공한다.
이 라벨들은 0부터 시작하는 숫자로 변환된다.

// const ADMIN = 0;
// const READ_ONLY = 1;
// const AUTHOR = 2;
/
enum Role { ADMIN = 'ADMIN', READ_ONLY = 100, AUTHOR = 'AUTHOR' };
//시작 숫자를 0으로 시작하지 않으려는 경우, 새로운 숫자를 할당할 수도 있다.
//5로 할당하면 다음 키는 6, 다음은 7
//텍스트도 할당 가능, 혼합도 가능 -> 사용자 정의 타입
/
const person = {
  name: 'Maximilian',
  age: 30,
  hobbies: ['Sports', 'Cooking'],
  role: Role.ADMIN
};
/
if (person.role === Role.AUTHOR) {
  console.log('is author');
}

Any 타입

타입스크립트에서 할당할 수 있는 타입 중 가장 유연한 타입
모든 종류의 값을 저장가능
타입배정도 딱히 필요없다.
단점은 타입스크립트가 주는 모든 장점을 any가 상쇄시켜 바닐라 자바스크립트를 쓰는 것과 다를 바 없다.

어떤 값이나 종류의 데이터가 어디에 저장될지 전혀 알 수 없는 경우에 대비하거나
런타임 검사를 수행하는 경우
런타임 도중 특정 값에 수행하고자 하는 작업의 범위를 좁히기 위해 any를 사용하고, 그 외의 경우에는 any를 쓰지 않는 게 좋다.

조합타입

숫자와 문자열 둘 중 하나가 될 수 있도록 타입 배정을 할 수 있습니다.

function combine(input: number | string, input: number|string){
	let result;
	if(typeof input1==='number' && typeof input2 === 'number'){
		result = input1 + input2;
//둘다 숫자라면 수학적 계산을 한다.
	}else{
		result = input1.toString()+input2.toString();
//하나라도 문자라면 둘다 문자열타입으로 바꿔서 연결만 해준다.
	}
	return result;
}

리터럴타입

유니언 타입을 리터럴 타입과 결합하여 사용한다.

리터럴 타입은 스트링이나 숫자 등과 같은 핵심 타입을 기반으로 합니다만 이 타입을 특정 목적으로 사용할 수 있습니다.

아무 문자열이 아닌 이 두 문자열만 특정하여 허용하고
다른 문자열 값은 허용되지 않습니다.

function combine(
	input1: number|string,
	input2: number|string,
	resultConversion: 'as-number'|'as-text' //리터럴타입
){
	let result;
	if(typeof input1==='number' && typeof input2 === 'number' || resultConversion==='as-number'){
		result = input1 + input2;
	}else{
		result = input1.toString()+input2.toString();
	}
	return result;
}
/
const combinedAges = combine(30,26,'as-number');
console.log(combineAges);
/
const combinedNames = combine('Max','Anna','as-text');
console.log(combineNames);

타입 알리어스, 사용자정의타입, 객체타입

유니언 타입을 저장할 수 있는 유니언 타입 → 타입알리어스(별칭)만들기
사용하기 전에 이 프로젝트의 경우 파일의 맨 위에 type 키워드를 입력하고 타입알리어스의 이름과, 여기로 인코딩하고자 하는 타입 지정 type Combineable = number;

유니언 타입과 함께 사용하면 사용자 정의 타입, 즉, 타입 알리어스에 유니언 타입을 저장할 수 있으므로 유니언 타입 대신 밑에 있는 Combinable을 참조한다. type Combineable = number|string;

장점 :
대신 사용할 수 있는 재사용 가능한 타입 별칭이 있습니다.
이를 통해 코드의 양을 줄일 수 있고 Combinable을 사용할 때 항상 동일한 타입이나
동일한 유형 설정을 참조할 수 있습니다.

type Combineable = number|string;
type ConversionDecriptor: 'as-number'|'as-text' //리터럴타입-타입알리어스
function combine(
	input1: Combineable,
	input2: Combineable,
	resultConversion: ConversionDecriptor
){
	let result;
	if(typeof input1==='number' && typeof input2 === 'number' || resultConversion==='as-number'){
		result = input1 + input2;
	}else{
		result = input1.toString()+input2.toString();
	}
	return result;
}
/
const combinedAges = combine(30,26,'as-number');
console.log(combineAges);
/
const combinedNames = combine('Max','Anna','as-text');
console.log(combineNames);

타입알리어스 및 객체타입
타입 별칭을 사용하여 타입을 직접 “생성”할 수 있습니다. 유니온 타입을 저장하는 것만 가능한 것이 아닙니다. 복잡할 수 있는 객체 타입에도 별칭을 붙일 수 있습니다.
타입 별칭을 사용하면 불필요한 반복을 피하고 타입을 중심에서 관리할 수 있습니다.

type User = { name: string; age: number };
const u1: User = { name: 'Max', age: 30 }; // this works!

코드단순화하기

function greet(user: { name: string; age: number }) {
  console.log('Hi, I am ' + user.name);
}
/
function isOlder(user: { name: string; age: number }, checkAge: number) {
  return checkAge > user.age;
//단순화 후
type User = { name: string; age: number };
function greet(user: User) {
  console.log('Hi, I am ' + user.name);
}
function isOlder(user: User, checkAge: number) {
  return checkAge > user.age;
}

함수 반환 타입 및 무효

함수에는 매개변수 타입과 반환타입이 있다.
반환 타입은 타입스크립트가 추론한다.
두 입력값 모두 number라면 타입스크립트는 결과가 number라고 추론합니다. 명시적으로 매개변수 뒤에 타입을 할당할 수도 있다.
추론한 타입과 명시적 타입이 일치하지 않으면 에러 발생

타입을 명시적으로 설정할 이유가 굳이 없다면 타입을 설정하는 대신 타입스크립트가 타입을 추론하게 하는 게 좋다.

자바스크립트에는 없는 타입인 void 타입 : 아무것도 반환하지 않는다. 자바스크립트에서는 undefined로 값이 출력된다.
함수에 의도적으로 반환문이 없다는 것을 의미한다.

function add(n1: number, n2: number): number{
	return n1+n2;
}

타입의 기능을 하는 함수

함수에 타입을 넣는 이유?
함수의 매개변수와 리턴값 타입을 명확히 하기 위해!

function add(n1:number, n2:number){
	return n1+n2;
}
let combineValues: (a:number, b:number) => number;
//함수의 매개변수 타입이 숫자이고, 리턴결과의 타입도 숫자라고 명시하는 함수
combineValues = add; //가능
//함수를 할당하는 경우, 그 함수가 리턴값이 있으면 가능하다. 함수결과가 void이면 안됨!
//combineValues = 5; 함수에 타입을 명시하기 전에는 이 코드도 가능했다.
console.log(combineValues(8,8)); //16

함수 타입 및 콜백

아무것도 반환하지 않지만 number를 인수로 취하는 함수타입 생성 → 콜백함수가 됨
이 콜백함수의 인수는 addandhandle의 결과값이다.

function addandhandle(n1:number, n2:number cd: (num: number)=>void){
	const result = n1+n2;
	cd(result);
}
addAndHandle(10,20,(result)=>{
	console.log(result);
}
//callback 타입에 void를 지정함으로써 기본적으로 여기서 반환할 수 있는 모든 결과를 무시한다.
//하지만 return result를 한다면, 콜백함수가 무언가를 반환한다.
//return 타입의 경우 무언가를 전달하는 것에 대해 그냥 무시할 수 없으므로 그냥 넘어갈 수 없는데.
//addAndHandle 함수에서 callback이 호출되는 위치를 보면,
//매개변수가 사용되고, 전체 타입스크립트가 callback 함수와 매개변수의 수와 타입에 대해 아주 엄격하며
//반환 타입에 대해 크게 간여하지 않는 것 때문이다.

알 수 없는 타입 = unknown

타입스크립트에서 기본 제공되는 any와는 다른 타입!
어떤 사용자가 무엇을 입력할지 알 수 없기 때문에 unknown
숫자일지 문자열일지 알 수 없고, 모든 것이 허용됨
알 수 없는 타입의 흥미로운 점은 에러 발생 없이 어떤 값이든 저장할 수 있다는 것

unknown은 any와는 다르게 작동!!
userName을 string으로 지정하더라도 unknown을 문자열로 확실히 인식되지 않는다.
unknown을 any로 바꾸면 에러가 사라진다. unknown은 any보다 좀 더 제한적
any는 타입스크립트의 아주 유연한 타입이며 타입 확인을 수행하지 않게 하기 때문
unknown을 사용하는 경우, userInput에 현재 저장된 타입을 확인해야 문자열을 원하는 변수에 할당가능

unknown이 any보다 나은 이유는 할 수 없는 작업을 알 수 있도록 타입 검사를 수행할 수 있기 때문
userInput이 항상 문자열인지 또는 문자열이나 숫자인지 미리 알 수 있다면,
unknown 대신 문자열이나 유니언 타입을 쓰는 게 좋다.

let userInput : unknown;
let userName : string;
userInput = 5; //타입이 모두 허용
userInput = "Max"; //타입이 모두 허용
//userName = userInput; //에러 발생
//추가적인 타입 검사 필요
if(typeod userInput === 'string') userName = userInput;

절대 타입 - never

never를 반환하며 반환값을 생성하지 않는다.
이런 작업을 수행함으로써 코드 품질의 관점에서 의도를 더 분명히 할 수 있으며
이 함수는 아무것도 반환하지 않고 기본적으로 스크립트나 스크립트의 일부를 충돌시키거나
망가트리기 위한 것임을 코드를 읽는 개발자가 알게 할 수 있습니다.

function generateError(message: string, code: number): never{
	throw{message: message, errorCode : code}; //throw는 콘솔에 에러를 넘기게 한다.
}
generateError("error!!", 500);
profile
신입 프론트엔드 웹 개발자입니다.

0개의 댓글

관련 채용 정보