# 시작
<실전 리액트 프로그래밍>에 있는 내용을 따라 타입스크립트를 공부해본다. 타입스크립트를 실행하는 환경은 아래 사이트에서 도움을 받았다. 기존에는 컴파일하고 실행하는 귀찮은 과정을 반복했는데 이 방식대로 하면 매우 간편해진다.
방법
ts-node를 설치한다.
npm install -g typescript
아래 명령어로 실행한다.
ts-node [해당ts파일이름].ts
결과
# 실습
// 93.tsconst size: number = 123;
const isBig: boolean = size >= 100;
const msg: string = isBig ? "크다" : "작다";
// @ : 1) 배열은 두 가지로 정의할 수 있다.const values: number[] = [1, 2, 3];
const values2: Array<number> = [1, 2, 3];
values.push('a');// @ : 타입 에러 2) 숫자 배열에 문자열로 입력하면 타입 에러// @ : 3) 문자열과 숫자로 구성된 튜플 타입 정의const data: [string, number] = [msg, size];
data[0].substr(1);
data[1].substr(1);// @ : 타입 에러 4) 두 번째 아이템의 타입은 숫자인데 문자열의 메서드를 호출하면 타입 에러
1) 배열은 두 가지로 정의할 수 있다.
2) 숫자 배열에 문자열로 입력하면 타입 에러
3) 문자열과 숫자로 구성된 튜플 타입 정의
4) 두 번째 아이템의 타입은 숫자인데 문자열의 메서드를 호출하면 타입 에러
null과 undefined
// 94.ts// @ : 1) undefined와 null은 타입으로 사용될 수 있다.let v1: undefined = undefined;
let v2: null = null;
v1 = 123;// @ : 타입 에러 2) undefined 타입에 숫자를 입력하면 타입 에러// @ : 3) undefined와 null 타입은 다른 타입과 함께 유니온 타입으로 정의할 때 많이 사용let v3: number | undefined = undefined;
v3 = 123;
1) undefined와 null은 타입으로 사용될 수 있다.
2) undefined 타입에 숫자를 입력하면 타입 에러
3) undefined와 null 타입은 다른 타입과 함께 유니온 타입으로 정의할 때 많이 사용
문자열 리터럴과 숫자 리터럴 타입
// 95.tslet v1: 10 | 20 | 30;// @ : 1)
v1 = 10;
v1 = 15;// @ : 타입 에러 2)let v2: '경찰관' | '소방관';// @ : 3)
v2 = '의사';// @ : 타입 에러
1) 숫자 10, 20, 30은 각각 타입으로 사용했다.2) 나머지 숫자는 입력될 수 없다.
3) 변수 v2를 문자열 리터럴 타입으로 정의했다.
any
// 96.tslet value: any;
value = 123;
value = "456";
value = () => {};
any 는 숫자, 문자열, 함수도 입력 가능하다. 실제로 타입을 알 수 없거나 타입 정의가 안된 외부 패키지를 사용할 때 유용하다.
void와 never
// 97.ts// @ : 1) 아무 값도 반환하지 않음 voidfunction f1(): void {
console.log("hello");
}
// @ : 2) 함수가 비정상적으로 종료되므로 neverfunction f2(): never {
throw new Error("some error");
}
// @ : 3) 함수가 종료되지 않으므로 neverfunction f3(): never {
while (true) {
// ...
}
}
1) 아무 값도 반환하지 않음 void
2) 함수가 비정상적으로 종료되므로 never
3) 함수가 종료되지 않으므로 never
object
// 98.tslet v: object;
v = { name: "abc" };
console.log(v.prop1);// @ : 타입 에러 1) 객체의 속성에 대한 정보가 없기 때문에 접근하면 타입에러가 발생한다.// @ : 속성 정보를 포함해서 타입 정의하기 위해서 interface를 사용해야 한다.
1) 객체의 속성에 대한 정보가 없기 때문에 접근하면 타입에러가 발생한다.
속성 정보를 포함해서 타입 정의하기 위해서 interface를 사용해야 한다.
교차 타입과 유니온 타입
// 99.ts// @ : 1) 타입은 3 | 5let v1: (1|3|5) & (3 | 5| 7)
v1 = 3;
// @ : 2) v1에는 3 또는 5가 아닌 값을 할당할 수 없음
v1 = 1;
1) 타입은 3 | 5
2) v1에는 3 또는 5가 아닌 값을 할당할 수 없음
type 키워드로 타입에 별칭 주기
// 910.ts
type Width = number | string// @ : 1) number | string 타입에 Width라는 별칭 부여let width : Width;// @ : 2) 일반적인 타입처럼 사용
width = 100;
width = '100px';
1) number | string 타입에 Width라는 별칭 부여
2) 일반적인 타입처럼 사용
922 열거형 타입
열거형 타입
// 911.ts// @ : 1) 열거형 타입을 이용하여 과일 정의
enum Fruit {
Apple,
Banana,
Orange,
}
// @ : 2) 열거형 타입의 원소인 Apple을 값으로 사용const v1: Fruit = Fruit.Apple;
console.log(typeof v1);// number// @ : 3) Apple을 타입으로 사용const v2: Fruit.Apple | Fruit.Banana = Fruit.Banana;
1) 열거형 타입을 이용하여 과일 정의
2) 열거형 타입의 원소인 Apple을 값으로 사용
3) Apple을 타입으로 사용
명시적으로 원소의 값 입력하기
// 912.ts
enum Fruit {
// @ : 1) enum의 첫번째에 값 할당하지 않으면 자동으로 0 할당
Apple,
// @ : 2) enum의 각 원소에 숫자 또는 문자열 할당 가능. 명시하지 않으면 이전 원소 + 1
Banana = 5,
Orange,
}
1) enum의 첫번째에 값 할당하지 않으면 자동으로 0 할당
2) enum의 각 원소에 숫자 또는 문자열 할당 가능. 명시하지 않으면 이전 원소 + 1
열거형 타입의 객체 사용하기
// 914.ts
enum Fruit {
Apple,
Banana = 5,
Orange,
}
// @ : 1) enum은 객체이므로 객체처럼 다룰 수 있다.console.log(Fruit.Banana);// 5console.log(Fruit["Banana"]);// 5// @ : 2) 각 원소의 이름과 값이 양방향 매핑되서 값으로 이름을 가져올 수 있다.console.log(Fruit[5]);// Banana
1) enum은 객체이므로 객체처럼 다룰 수 있다.
2) 각 원소의 이름과 값이 양방향 매핑되서 값으로 이름을 가져올 수 있다.
열거형 타입의 값으로 문자열 할당하기
// 915.ts
enum Language {
Korean = "ko",
English = "en",
Japanese = "jp",
}
enum 의 원소에 문자열을 입력하는 경우에는 단방향 매핑된다. 이는 서로 다른 원소의 이름 또는 값이 같으면 충돌이 일어나기 때문이다.
열거형 타입을 위한 유틸리티 함수
// 917.tsfunction getEnumLength(enumObject: any) {
const keys = Object.keys(enumObject);
// @ : enum의 값이 숫자이면 두 개씩 들어가므로 문자열만 계산return keys.reduce(
// @ : 1) 원소가 숫자면 양방향 매핑이므로 주의. 객체의 속성값이 문자열인 경우만 계산하면 열거형의 원소 개수를 구할 수 있다.
(acc, key) => (typeof enumObject[key] === "string" ? acc + 1 : acc),
0
);
}
열거형 타입에 존재하는 값인지 검사하는 함수
// 918.tsfunction isValidEnumValue(enumObject: any, value: number | string) {
if (typeof value === "number") {
// @ : 1) 값이 숫자이면 양방향 매핑인지 검사한다.return !!enumObject[value];
} else {
return Object.keys(enumObject)
.filter((key) => isNaN(Number(key)))
// @ : 2) 값이 문자열이면 양방향 매핑에 의해 생성된 키를 제거하고 해당 값이 존재하는지 검사
.some((key) => enumObject[key] === value);
}
}
getEnumLength 함수와 isValidEnumValue 함수의 사용 예
// 919.tsimport isValidEnumValue from "./918";
import getEnumLength from "./917";
enum Fruit {
Apple,
Banana,
Orange,
}
enum Language {
Korean = "ko",
English = "en",
Japanese = "jp",
}
console.log(getEnumLength(Fruit), getEnumLength(Language));
// @ : 3 3 1) 열거형 타입 원소 개수 출력console.log("1 in Fruit:", isValidEnumValue(Fruit, 1));
// @ : 2) 열거형 타입에 존재하는 값이 맞는지 검사// @ : trueconsole.log("5 in Fruit:", isValidEnumValue(Fruit, 5));
// @ : falseconsole.log("ko in Language:", isValidEnumValue(Language, "ko"));
// @ : trueconsole.log("Korean in Language:", isValidEnumValue(Language, "Korean"));
상수 열거형 타입
열거형 타입은 컴파일 후에도 남아있기 때문에 번들 파일의 크기가 불필요하게 커진다. 열거형 타입의 객체에 접근하지 않는다면 삭제해도 된다. const 열거형 타입을 사용하면 된다.
// 923.tsimport getEnumLength from "./917";
const enum Fruit {
Apple,
Banana,
Orange,
}
// @ : 타입 에러 1) 열거형 타입을 상수로 정의하면 열거형 타입의 객체를 사용할 수 없다.console.log(getEnumLength(Fruit));