23.07.27
2-1 ~ 2-3 컴파일러, tsc
TS 컴파일러인 tsc는 JS로 변환함
원래 컴파일러는 기계어로 변환되어야 하는데 JS는 동적 언어(= 인터프리터 언어)이기 때문에 기계어로 변환될 필요가 없음
그래서 Node.js나 크롬에서 JS를 실행할 때는 v8엔진이 코드 해석 및 실행을 해서
compilerOptions - strict
compilerOptions - sourceMap
위 두 옵션 모두 true로 설정하는 것을 권장
tsc —init을 실행하면 tsconfig.json이 생성됨
그렇다면 여기서 tsconfig.json란 ? TS 프로젝트의 설정 파일로 프로젝트의 컴파일 옵션 및 입력 파일들을 정의하는데 사용
tsconfig.json 주요 옵션
매뉴얼 https://www.typescriptlang.org/ko/tsconfig
옵션 종류
1. compilerOptions - target 옵션
ES6 이전 버전들은 Common JS라고 불림
그 이후 버전들은 그냥 ES6, ES7 or ES2015, ES2016 으로 불림
옵션을 정할 때는 TS가 어느 환경에서 실행이 되어야하는지를 고려해야 함
2-4 ~ 2-6 .d.ts 파일
레거시한 JS 파일을 TS로 사용하기 위해서는 .d.ts 파일을 이용하여 하위 호환성을 확보하면 됨
그렇다면 .d.ts 파일이란 ? TypeScript 타입 정의 파일 => 즉, JavaScript 라이브러리에 대한 타입 정보를 제공
.d.ts 파일로 tsc는 (1) 외부 라이브러리의 함수 타입 정보 (2) 외부 라이브러리 클래스 타입 정보 (3) 외부 라이브러리 객체 타입 정보 뿐만 아니라, (4) .d.ts 파일로 외부 라이브러리의 타입 추론 까지 가능하며
이 파일을 제공하면 TS에서도 JS라이브러리를 코드 한줄도 수정할 필요없이 그대로 사용할 수 있음 ⭐️
이게 안된다면 호환성이 안좋아 인기가 없었을듯
npm init -y
=> Node.js 프로젝트 만드는 명령어
tsc --init
=> TS 프로젝트 만드는 명령어
"allowJs": TS 프로젝트에서 JS를 허락할건지 여부
"checkJs": JS 파일 타입 체크할건지 여부
/**
tsc --init --rootDir ./src --outDir ./dist --esModuleInterop --module commonjs --strict true --allowJS true --checkJS true
function calculateAverage(student: Student): number {
const sum =
student.scores.korean +
student.scores.math +
student.scores.society +
student.scores.science +
student.scores.english;
// const average = sum / 5;
// 하드코딩하지 않게
const average = sum / Object.keys(student.scores).length;
return average;
}
Object.keys 라는
3-1. 타입을 왜 제대로 알아야 하는가
변수는 데이터를 저장하는 공간
변수에는 다양한 데이터 타입이 저장될 수 있음
타입 안정성 = 코드가 예상한 대로 동작함을 보장하는 것
타입을 제대로 이해하고 활용한다면 타입 안정성이 높을 것이고 자연스럽게 테스트, 디버깅 시간도 줄일 수 있음
원활한 협업 가능
3-2 ~ 3-3. 기본 타입
1. boolean : true, false => 2가지의 상태를 표현하고 싶은 경우로 조건문, 비교 연산에서 주로 사용
3가지 이상의 상태를 표현하고 싶은 경우는 enum, string …
2. number : 숫자
3. string : 문자 (* 템플릿 리터럴을 사용할 땐 ``사용)
4. 배열 : 기본타입에 []가 붙은 형태의 타입
5. 튜플 (tuple) : 서로 다른 타입의 원소를 순서에 맞게 가질 수 있는 특수한 형태의 배열
배열은 같은 타입의 원소 데이터만 가질 수 있지만 튜플은 상관없음
const person: [string, number, boolean] = ['Spartan', 25, false];
const person2: [string, number, boolean] = [25, 'Spartan', false]; // 오류!
이런식으로 어떤 타입의 원소를 허용할 것인지 정의해주고 할당해주면 됨
그러나 정의된 데이터 타입의 개수와 순서에 맞추어 할당하는 것이 필수
또한 push를 사용하여 개수를 더 추가할 순 있지만 구조가 내부적으로 변경되니 좋은 방법은 아님
enum UserRole {
ADMIN = "ADMIN",
EDITOR = "EDITOR",
USER = "USER",
}
enum UserLevel {
NOT_OPERATOR, // 0 // 값을 대입하지 않으면 0
OPERATOR // 1 // 대입하면 1
}
function checkPermission(userRole: UserRole, userLevel: UserLevel): void {
if (userLevel === UserLevel.NOT_OPERATOR) {
console.log('당신은 일반 사용자 레벨이에요');
} else {
console.log('당신은 운영자 레벨이군요');
}
if (userRole === UserRole.ADMIN) {
console.log("당신은 어드민이군요");
} else if (userRole === UserRole.EDITOR) {
console.log("당신은 에디터에요");
} else {
console.log("당신은 사용자군요");
}
}
const userRole: UserRole = UserRole.EDITOR;
const userLevel: UserLevel = UserLevel.NOT_OPERATOR;
checkPermission(userRole, userLevel);
이렇듯 enum은 명확하게 관련된 상수값들을 그룹화하고자 할 때 사용하는게 좋음
그러나 값의 수가 많지 않고, 값들 사이의 관계가 뚜렷하지 않으면 사용하지 않는게 좋음 (=> 즉 카테고라이징 가능한 값들에서만 사용하기)
3-4 const, readonly
let : 변수, 값 변경 가능, 재할당 불가
const : 상수, 값 변경 불가 ( “= 연산자”로 다시 할당이 불가능하다는 의미), 재할당 불가
const num: number = 5;
console.log(num); // 출력: 5
num = 10; // 에러: 'num'은 const로 선언되었으므로 다시 할당될 수 없어요!
const nums: number[] = [];
console.log(nums); // 출력: []
nums.push(1); // 할당은 되지 않아도 배열에 데이터를 추가/삭제하는 것은 문제가 안됩니다!
nums.push(2); // 은근히 헷갈릴 수 있지만 = 연산자 기준으로만 생각하면 매우 쉬워요!
console.log(nums); // 출력: [1, 2]
nums = []; // 에러: 'nums'는 const로 선언되었으므로 다시 할당될 수 없어요!
“= 연산자”를 사용하여 재할당은 불가하지만 배열 안에서 메서드를 사용하여 데이터 추가/삭제는 가능
========================
readonly : 객체의 속성을 불변으로 만드는 데 사용 => 클래스의 속성이나 인터페이스의 속성을 변경할 수 없게 만듦
class Person { // 클래스는 다른 강의에서 자세히 설명해드릴게요!
readonly name: string;
readonly age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
const person = new Person('Spartan', 30);
console.log(person.name); // 출력: 'Spartan'
console.log(person.age); // 출력: 30
person.name = 'Jane'; // 에러: 'name'은 readonly 속성이므로 다시 할당할 수 없어요!
person.age = 25; // 에러: 'age'은 readonly 속성이므로 다시 할당할 수 없어요!
readonly를 const로 치환하면 어떻게 되나요? 이렇게 쓰면 안되나요?
3-5 any, unknown, union
가변적인 타입의 데이터를 저장하고 싶다면 unknown
가변적인 타입을 일일이 정의할 수 있다면 union
let anything: any;
anything = 5; // 최초에는 숫자를 넣었지만
anything = 'Hello'; // 문자열도 들어가고요
anything = { id: 1, name: 'John' }; // JSON도 들어가네요
=> 이러한 경우가 정말 많이 없긴하지만 NoSQL 같은 데이터를 받아들일 때 사용할 수 있음
let unknownValue: unknown = '나는 문자열이지롱!';
console.log(unknownValue); // 나는 문자열이지롱!
let stringValue: string;
stringValue = unknownValue; // 에러 발생! unknownValue가 string임이 보장이 안되기 때문!
stringValue = unknownValue as string;
console.log(stringValue); // 나는 문자열이지롱!
let unknownValue: unknown = '나는 문자열이지롱!';
let stringValue: string;
if (typeof unknownValue === 'string') {
stringValue = unknownValue;
console.log('unknownValue는 문자열이네요~');
} else {
console.log('unknownValue는 문자열이 아니었습니다~');
}
unknown 타입이 그나마 재할당을 할 때 타입 체크가 되어서 안전함을 보장해요.
하지만, unknown 타입도 결국 재할당이 일어나지 않으면 타입 안전성이 보장이 되지 않음
union 은 여러 타입 중 하나를 가질 수 있는 변수를 선언할 때 사용됩니다!
union은 | 연산자를 사용하여 여러 타입을 결합하여 표현합니다.
type StringOrNumber = string | number; // 원한다면 | boolean 이런식으로 타입 추가가 가능해요!
function processValue(value: StringOrNumber) {
if (typeof value === 'string') {
// value는 여기서 string 타입으로 간주
console.log('String value:', value);
} else if (typeof value === 'number') {
// value는 여기서 number 타입으로 간주
console.log('Number value:', value);
}
}
processValue('Hello');
processValue(42);