Weekly Learned - L택배 크롤링하기

쇼핑몰 사이트를 운영하다보니 다들 계약한 택배사가 달라서 여러 택배사의 배송완료 플래그를 받아야 할 경우가 있습니다.

그런데 L 택배가 H택배를 인수 후 시스템을 대대적으로 개편을 했는지 정상적으로 크롤링이 안되는 경우가 발생 했습니다.

몇시간의 삽질끝에 대충 원리를 알게 됐습니다.

POST로 요청을 함 -> 서버에서 데이터를 가져옴(클라이언트에서는 1초 대기) -> 가져온 값을 보여줌(1회성)

즉, 다이렉트로 결과 URL에 요청을 하면 안되고 먼저 첫번째 URL에 요청을 하고 서버에서 불러올 시간을 준 뒤 다음 가져온값을 보여줍니다.

약 서버에서 불러올 시간은 평균적으로 1.5초정도 되는 것으로 예상이 됐는데, 여기저기 뺑뺑이 돌릴 경우를 감안하면 3초정도 대기텀을 주면 될 것 같습니다.

요청시 파라미터는 두개가 필요하며 첫번째 POST 요청 시 택배번호와 action의 “~~~submit”이라는 변수가 필요합니다.(고정값)

대기 후 action이 “linksubmit”으로 변경되서 요청을 주면 됩니다.

대충 의사코드로 짜면 다음과 같이 적용하면 되겠죠.

1
2
3
4
5
6
7
8
9
10
11
12
JAVA 기준

jsoup.post('REST URL형식의 요청 URL')
.data('택배번호변수','실제번호')
.data('action','~~~submit');

//대기
Thread.sleep(1000 * 3);

jsoup.post('REST URL형식의 요청 URL') //URL 변경 X
.data('택배번호변수','실제번호')
.data('action','~~~linksubmit') //요부분만 강제로 변경

이런식으로 코드를 작성하면 정상적으로 불러올 수 있을겁니다.

타입스크립트 5일차 - 클래스

타입스크립트의 객체지향 지원

제 생각은 역시 C#을 만들었고 그 전에도 많은 객체지향언어를 다룬 사람들 답게 여러가지 객체지향적인 기능을 지원합니다.
ES6 에서 클래스를 만들었지만 타입스크립트에서는 좀 더 지원합니다.
구체적으로 인터페이스(+구현), 접근제한자, final(변경불가능한 상수)를 지원합니다.

SOLID, 디자인패턴 등 여러가지 객체지향적 특징은 나중에 정리할 일이 있을것 같습니다. 물론 여기서는 말고요

클래스 선언과 객체 생성

ES6의 문법을 그대로 따라갑니다.

책 따라서 Rectangle 클래스를 만들면 바로 문법을 알 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
class Rectangle {
x: number;
y: number;

constructor(x: number, y: number) {
this.x = x;
this.y = y;
}

getArea(): number { return this.x * this.y; }
}

let rectangle = new Rectangle(1,5); //객체생성

생성된 객체는 메모리에 위치하며 객체 참조가 참조변수에 할당되는 인스턴스화를 거칩니다.

접근제한자

C#은 private, protected, Internal, public가 있지만 타입스크립트에서는 Internal을 구현하기가 어렵기 때문에 존재하지 않습니다.
즉, private은 현재 클래스에서만 접근할 수 있고 protected 자식 클래스에서 접근 가능하며 public은 다 접근할 수 있습니다.
기본적인 생성방법은 다음과 같습니다.

1
2
3
private a = 0;
protected b = 0;
public c = 0;

물론 클래스 안에서 쓰셔야 합니다.
그리고 생성자 매개변수에 접근제한자를 추가하여 멤버 변수가 되도록 하게 되는 역할도 가능합니다.

1
2
3
4
5
6
7
8
9
10
11
class Cube {
constructor(public width: number, protected length: number, private height: number) {
}
getVolume() {
return this.width * this.length * this.height;
}
}

let [pWidth, pLength, pHeight] = [1, 2, 3];
let cube = new Cube(pWidth, pLength, pHeight);
console.log(cube.getVolume());

클래스 매개변수로 width, length, height 세개를 선언해서 getvolume 메소드로 넓이를 구하는 클래스입니다.
저렇게 선언하면 실제로 width, length, height를 선언하지 않아도 클래스 변수로 쓸 수 있습니다.

private, protected를 외부에서 쓸 수 없다

추상클래스

추상메소드를 가지고 있는 클래스를 추상클래스라고 합니다.

추상클래스는 객체 생성을 할 수 없게 만들며 공통으로 사용할 로직을 정의하고 싶을 때 쓰면 됩니다만 대부분은 거의 쓸 일이 없을 것이라 생각됩니다.
추상메소드에는 abstract 키워드를 쓰며 static, 접근제한자를 쓸 수 없습니다.

인터페이스

인터페이스는 객체지향언어에서는 지원하지만 자바스크립트에서는 지원하지 않았으며 타입스크립트에 추가됐습니다.
인터페이스에는 선언만 존재하며 변수와 메소드를 선언할 수 있지만 접근 제한자는 설정할 수 없습니다. 그리고 인터페이스를 다중으로 구현이 가능합니다.

나머지 특징은 기본적으로 객체지향의 인터페이스와 같으며 간단하게 써보겠습니다.

1
2
3
4
5
6
interface Icar {
name: string;
}

let mCar: Icar = { name: "car" };
console.log(mCar);

위의 코드에서 인터페이스는 타입스크립트만의 특징이므로 컴파일을 하면 날라가서 필요한 코드만 남게 됩니다.

1
2
let mCar = { name: "car" };
console.log(mCar);

이런식으로 컴파일됩니다.

get, set

C#에서는 POCO 형식으로, 자바에서는 POJO 형식으로 대부분 쓰고 있는 형식입니다.
클래스 내부변수를 선언하고 get,set 메소드를 사용하여 변수안에 값을 넣고 빼는 방식입니다.
언어 사양에 의해 강제되는 것 이외의 제한 사항에 구속받지 않는 객체입니다.

사용하는 이유는 간단하기 때문에 다른 라이브러리, 인터페이스 또는 주석에 의존하지 않습니다. 이렇게하면 여러 프로젝트 유형 (웹, 데스크탑, 콘솔 등)에서 재사용 할 수있는 가능성이 높아집니다.
타입스크립트도 이러한 형식으로 쓸 수 있도록 ES6 이후로 Object를 지원합니다.

저는 VSCODE에서 사용한다면 TypeScript's Getters and Setters Object Oriented Programming Style 같은 자동으로 만들어주는 get,set generator 플러그인을 추천합니다.
이클립스나 다른 툴이라면 자동으로 만들어주는 툴이 내장되어 있으니 바로 쓰시면 될 것 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class student {
private sName: string;

//generator style
public getSName(): string {
return this.sName;
}

public setSName(sName: string): void {
this.sName = sName;
}

//ES6 style
get name() {
return this.sName;
}
set name(sName) {
this.sName = sName;
}
}

여러분이 원하는 스타일로 쓰시면 됩니다.

static과 readonly

객체지향 언어와 같이 static을 사용하면 객체생성없이 메소드를 사용할 수 있도록 해줍니다.
이러한 키워드를 사용하여 그 메소드에 하나만 있어야 할 변수나 클래스에 씁니다.

마지막으로 readonly를 사용하여 타 언어의 final과 같은 효과를 낼 수 있습니다.
즉, 상수에서 사용합니다.

const와 다른 점이 몇가지 있습니다.

  • readonly는 초기화가 선택입니다.
  • 값의 재할당이 가능합니다.
  • 컴파일 후 사라집니다.

사용처는 인터페이스의 멤버 변수, 클래스의 멤버 변수에 사용합니다.

결론

객체지향 형식으로 쉽게 코딩할 수 있도록 도와주는 클래스와 기타 기능에 대해 알아 봤습니다.
다음에는 8장 모듈로 뵙겠습니다.

Weekly Learned - JS GET, SET시 삽질

this...

심심해서 JS가지고 놀다가 class를 사용해봤는데 문제가 있었습니다.

자바처럼 this.변수명을 그대로 쓰면 문제가 되네요.

생성자는 상관없는것 같은데 GET, SET 메소드에서는 local변수는 다르게 써야할 것 같습니다.

혹은 private으로 내부변수를 선언하면 될 것 같습니다.

정확히 ES6에서는 그렇게 써야 되는 문법인데 잘 몰랐던 탓이겠지요.

즉 저 스크린샷처럼 다르게 써줘야되고 this.title = title시 정상적으로 작동하지 않는 현상이 발생하게 됩니다.

조금 더 알아봐야겠네요

타입스크립트 4일차 - 함수

함수

타입스크립트의 함수는 자바스크립트의 함수를 그대로 사용하면서 반환값이나 파라미터에 타입을 추가함으로써 타입안전성을 높였습니다.
이 시간에는 함수를 간단하게 알아보겠습니다.

함수의 선언

자바스크립트에서는 기명함수와 익명함수를 선언할 수 있습니다.

1
function 함수명(파라미터){}

쉽게 말해서 위의 함수뼈대에서 함수명이 없으면 익명, 있으면 기명함수가 됩니다. 그리고 함수에서 자바스크립트의 특징인 호이스팅이 발생하게 됩니다.
즉, 호이스팅이 발생해서 선언전에도 함수의 사용이 가능하게 됩니다.
이것을 막기 위해서 아래와 같이 변수에 할당하여 사용하게 됩니다.

1
let 변수 = function (파라미터){}

함수의 직접사용 예제를 보겠습니다.

1
2
3
4
5
6
function ambiguity(str){
return str + 1000;
}

let result = ambiguity("1000");
console.log(result);

위와 같은 자바스크립트 함수에서 타입이 없기 때문에 무엇이 나올지 하나씩 디버깅하면서 오류발생하면 흐미… 하면서 잘 작동되기를 빌어야 하는데요.
이러한 기도를 조금이라도 줄이기 위해서 타입스크립트에서는 타입을 선언하여 사용할 수 있습니다.
타입스크립트 형으로 수정하면 다음과 같습니다.

1
2
3
4
5
6
function ambiguity(str: number) : number{
return str + 1000;
}

let result = ambiguity(1000);
console.log(result);

위와 같이 타입을 강제함으로써 불필요한 연산을 생략할 수 있게 됩니다.

  • 함수의 파라미터의 타입에 대한 검증
  • 만약 반환값이 변수라면 그 변수에 대한 검증

이러한 노가다를 줄여서 빠르게 개발할 수 있도록 도와줍니다.

파라미터(매개변수)

파라미터와 매개변수는 거의 동일하게 쓰인다고 저는 생각합니다만…
아무튼 타입스크립트에서는 앞에서 본것과 같이 기본 초기화 매개변수를 선언할 수 있습니다.

1
param1: number = 2

여기서 param1이라는 로컬변수에 number 타입을 강제하고 숫자 2를 기본으로 대입하였습니다.
이 기본값의 선언은 ES6의 기능이므로 ES6이상이라면 유사하게 컴파일이 가능합니다.

ES6에서 추가된 개수가 정해지지 않은 인수를 배열로 받을 수 있는 ...도 사용할 수 있습니다.

1
2
3
4
5
function concat(...rest){
console.log(rest.join("/"));
}

concat("a","b",1,2,true,false);

위의 식에서 rest에 모든 값이 들어오게 되고 rest를 활용하여 원하는 작업을 진행할 수 있습니다.

선택 매개변수

자바스크립트와 다르게 타입스크립트에서 함수 호출 시 선언된 갯수의 파라미터를 갖는 함수만 호출해서 쓸 수 있습니다.
그런데 가끔 파라미터가 몇개가 들어올 지 모르는 경우가 생깁니다. 그래서 ? 라는 선택매개변수를 지원합니다.

1
function 함수명(변수1: any, 변수2?: any){}

위의 식에서 변수2는 들어와도 되고 안들어와도 되는 선택매개변수가 됩니다.
즉, 함수명(파라미터1)함수명(파라미터2)는 모두 사용 가능하다는 뜻이죠.
딱하나 제약이 있다면 타입스크립트에서는 기본값과 선택매개변수를 동시에 쓸 수 없도록 해놓았습니다. 들어올지도 안들어올지도 모르는데 초기에 값을 줄 수는 없다는 얘기겠죠.

화살표함수

타 언어에서 람다식이라 불리는 화살표 함수를 지원합니다. 사용법은 다음과 같습니다.

1
(변수) => { // TODO }

익숙해지면 정말 편리하게 쓸 수 있는데요. 기본적으로 익명함수로 사용하게 되며 여기에 타입을 선언할 수 있습니다.
즉, 변수: 타입 이렇게 되겠네요.
추가적으로 reduce, filter 등의 연산도 지원하고 있어 for문과 다르게 객체의 순회를 좀 더 편하게 할 수 있도록 도와줍니다.

함수 오버로드와 오버라이드

자바나 C#에서는 함수의 오버로드와 오버라이드를 지원합니다.
타입스크립트에서도 C#의 영향을 받아서 그런지 유사하게 지원하고 있습니다. 그리고 컴파일 시 최적의 함수를 선택하도록 지원해서 JS실행시 런타임 비용이 발생하지 않도록 하고 있습니다.

오버로드

오버로드란 같은 이름의 함수를 여러개 선언해서 골라 쓸 수 있도록 하는 방법입니다.
바로 사용예제를 보겠습니다.

1
2
3
4
5
function add(a: string): string;
function add(a: number): number;
function add(a: any): any {
//TODO
}

위와 같이 같은 함수명으로 타입과 리턴타입만 다르게하여 선언이 가능하며 여기에 선택 매개변수를 활용하여 개수에 변화를 줘서 같은 리턴타입으로 여러개의 오버로드를 할 수 있습니다.

오버라이드

오버라이드란 부모의 함수를 내용만 뜯어고쳐서 사용할 수 있도록 하는 방법입니다.
타입스크립트는 그냥 타 언어와 같이 상속해서 쓰면 됩니다.
아래에서 간단한 예제를 보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A {
g(){
console.log('A');
}
}

class B extends A{
g(){
console.log('b');
}
}

let val:A = new B();
val.g();

B의 객체를 생성해서 함수를 사용하게 되면 A에서 선언된 함수를 사용하지 않고 B의 함수를 사용합니다.
만약 상위 클래스의 함수나 속성등을 사용하고 싶으시다면 _super를 사용하시면 불러올 수 있습니다.

마무리

간단하게 함수에 대해서 알아봤습니다.
일급객체, 호이스팅, 콜백함수 등 다른 함수에 관한것들은 JS를 한번 참조하시면 좋을 것 같습니다.
다음에는 클래스와 인터페이스 입니다.

Weekly Learned - JSTL DEBUG(intellij)

JSTL 디버깅하기

이클립스에서는 안해봐서 모르겠으나 인텔리j 기준으로 다음과 같이 디버그 하면 됩니다.

그 줄 말고 조오금 아래쪽에 찍고 디버깅이 걸린 상태에서 수많은 변수 중에 원래 디버깅하고자 하는 태그를 찾으면 됩니다.

foreach debug

위에서는 foreach문에 item이 정상적으로 들어오는지 알고 싶어서 디버깅하고자 합니다.

저기서 foreach 변수를 찾고 item변수를 찾으면 쉽게 알 수 있습니다.

item변수가 없더라도 하위 변수 찾다보면 나옵니다.

타입스크립트 3일차 - 연산자

연산자

타입스크립트는 자바스크립트의 최신 연산자를 기반으로 객체나 배열을 더욱 쉽게 다룰 수 있습니다.

산술연산자

기본적으로 가감승제(+-*/)와 나머지(%)는 기본적으로 지원합니다.
거기에 ES7에서 추가된 지수연산자인 **이 추가되서 Math.pow()를 대체해 사용할 수 있습니다.

지수연산자만 한번 사용해볼까요?

새로운 지수연산자

그리고 타입스크립트에서는 자바스크립트와 다르게 문자열과 불린(boolean)값을 연산할 수 없습니다.
이처럼 엄격한 타입검사로 연산자를 사용할 때 안전성을 높입니다.

비교연산자

자바스크립트와 같습니다. 간단하게 적어본다면

  • a==b : a와 b가 같은 값인지 비교
  • a!=b : a와 b가 값이 다른지 비교
  • a===b : a와 b가 값과 타입이 같은지 비교
  • a!==b : a와 b가 값과 타입이 다른지 비교
  • a > b : a가 b보다 큰지
  • a < b : a가 b보다 작은지
  • a >= b : a가 b보다 크거나 같은지
  • a <= b : a가 b보다 작거나 같은지

JS기준으로 다음과 같습니다만 타입스크립트에서는 조금 다른점이 있습니다.
바로 ==연산자를 사용하여 비교 시 타입이 달라 반드시 false가 나올 경우 오류메시지로 표시합니다.
만약 1과 “1”을 비교했을 경우도 "1"이기 때문에 숫자 1과 비교시에 반드시 틀린것이죠.
즉, 타입스크립트에서는 타입이 다른 피연산자 간에는 비교 연산이 불가능 하다는 것이고 될 수 있으면 ===를 쓰도록 책도 추천하고 Lint도 추천하도 다른 사람들도 추천하고 있습니다.

숫자와 문자열의 ==연산

논리연산자

JS와 같습니다

  • a && b : a와 b가 참이여야 true
  • a || b : a와 b 둘 중하나가 참이면 true
  • !a : a의 반대로 출력(not a)

JS와 사용법도 같고 타입스크립트의 엄격한 타입검사도 사용하지 않습니다.
즉, 타입이 달라도 무리없이 논리연산자의 적용이 가능합니다.

예를 들어

1
2
3
4
5
if (1 && "0") {
console.log('true');
} else {
console.log('false');
}

다음과 같은 조건문이 있다고 하면 값은 true를 떨궈줍니다.
왜냐 라고 물으신다면 JS에서는 변수 단독으로 선택 시 전에 말했듯이 false, undefined, 0 등의 값에서만 false로 인식하기 때문에 해당 조건문에서는 숫자 1(true)과 문자열 0(true)의 값으로 계산하기 되는 것이죠.

조건연산자

말이 조건연산자이지 타 언어에서 삼항연산자로 배웠던 연산자입니다.
사용법만 간단히 알고 넘어가겠습니다.

1
판별 조건 ? 참일때 처리 : 거짓일떄 처리

디스트럭처링

디스트럭처링이란 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 방법입니다.
말이 어려운데 제생각에는 조금 쉽게 풀어쓰면 속성을 여러개의 변수로 한번에 선언해서 편하게 쓰고 싶다. 정도 될 것 같네요.

JS에서는 크게 객체와 배열의 디스트럭처링으로 나눌 수 있으며 타입스크립트도 같이 쓰고 있습니다.
여기에 추가적으로 타입을 사용하여 안전성을 좀 더 보충해주는 것이죠.

객체 디스트럭처링

객체 디스트럭처링은 객체 리터럴에서 변수명에 대응하는 속성을 추출해 변수로 할당할 때 유용하다고 합니다.
기본적인 JS 사용법은 다음과 같습니다.

1
2
()는 생략가능, []는 1개이상 필요하면 추가생성가능
let { 속성1 (: 새로운변수1)[, 속성2 (: 새로운변수2).....]} = 값을 할당할 객체;

그리고 기본값을 추가가능합니다. 그렇게 된다면 사용법은 다음과 같습니다.

1
let { 속성1 (: 새로운변수1)(= 디폴트값1) [, 속성2 (: 새로운변수2)(= 디폴트값2) .....]} = 값을 할당할 객체;

기본값을 사용하는 식에서 새로운 변수와 디폴트값은 동시에 선언할수도 있고 원하는 것만 하나씩 선언도 가능합니다.

그럼 이제 타입스크립트 답게 타입을 넣어서 해보겠습니다.

1
2
3
4
5
무조건 함수파라미터에만 사용가능합니다.
type C = {a: number, b:string}
function test({ a,b } : C): void{
//TODO
}

배열 디스트럭처링

이번에는 배열의 값을 동시에 쉽게 뽑아 사용할 수 있도록 도와주는 문법입니다.
사용법은 다음과 같습니다.

1
let [변수명1 (= 기본값1), 변수명2 (= 기본값2), 변수명3 (= 기본값3) .....] = 배열객체;

객체가 아니고 배열이기 떄문에 {} 대신 []을 쓰는 것을 잊지마시기 바랍니다.
그리고 이 디스트럭처링을 사용하면 배열 요소를 함수에 파라미터로 쉽게 줄 수 있습니다.

함수 파라미터와 배열 디스트럭처링+타입

전개연산자

타입스크립트는 ES6의 전개연산자인 ...을 지원합니다.
이 연산자는 합치기와 디스트럭처링에서 사용하며 배열과 객체 모두 사용할 수 있습니다.

먼저 배열에서 먼저 전개연산자를 사용해보겠습니다.
아래의 스샷에서 쉽게 확인하실 수 있습니다.

배열의 전개연산자

위의 연산을 보시면 전개연산자를 적용한 arr2는 arr이 뒤로 합쳐진 것을 보실 수 있고 디스트럭처링의 전개연산자에서는 처음 가져가는 first를 제외한 나머지 값을 가지고 있는 것을 볼 수 있습니다.

다음은 객체입니다.

객체의 전개연산자

객체도 마찬가지로 확인이 가능하고 객체의 속성까지 같이 가져가는 것을 볼 수 있습니다.

이것으로 연산자에 대한 설명을 마치고 다음에는 함수로 돌아오겠습니다.

네티 알아보기 6일차 - Spring + Netty

Intro

MVC 패턴을 쉽게 구현할수 있도록 도와주며 한국에서 java 웹 프레임워크로 가장 많이 사용되는 스프링과 Netty를 연동해 보겠습니다.
환경은 Maven + Spring + Netty 입니다.

Maven 연동

pom.xml에 Netty를 등록합니다.

1
2
3
4
5
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.32.Final</version>
</dependency>

환경설정

기본적으로 컨텍스트를 스프링이 생성할 수 있도록 설정해야되고 Netty의 기본 환경설정을 해줘야 합니다.
먼저 스프링쪽의 간단한 설정을 해보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Configuration
@ComponentScan
@PropertySource("클래스명")
public class SpringSample {

@Value("thread.count")
private int threadCount;

@Value("tcp.port")
private int port;

@Bean(name = "tcpSocketAddr")
public InetSocketAddress tcpPort() {
return new InetSocketAddress(port);
}

@Bean
Public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();
}
}

다음으로 부트스트랩의 설정이 필요합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class NettySpringSample {

@Autowired
@Qualifier("tcpSocketAddr")
private InetSocketAddress port;

public void start(){
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();

try{
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new TelnetInitializer());

ChannelFuture future = b.bind(port).sync();
future.channel().closeFuture().sync();
}catch (Exception ex){
ex.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

마지막으로 컨텍스트의 설정입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class NettyContextSample {
public static void main(String[] args) {
try(AbstractApplicationContext context =
new AnnotationConfigApplicationContext(SpringSample.class)){
context.registerShutdownHook();

NettySpringSample sample = context.getBean(NettySpringSample.class);
sample.start();

}catch (RuntimeException ex){
ex.printStackTrace();
}
}
}

이상으로 네티에 대한 것을 마치겠습니다.
소스의 경우 알맞은 조금 수정이 필요합니다.

타입스크립트 2 - 제어문, 반복문

타입스크립트의 제어문

제어문에는 크게 보면 조건문과 반복문으로 볼 수 있습니다.
기본적으로 타 언어와 동작하는것은 같습니다만 타입스크립트에서의 제어문을 보도록 하겠습니다.

조건문

  • if

조건의 참과 거짓에 따라 분기를 수행하는 것은 똑같습니다.
기본적으로 조건에는 참과 거짓을 판단할 수 있는 boolean타입이 와야 한다고 알고 있습니다.

1
2
3
4
5
6
7
if (조건) {
//하고싶은것
} else if(조건) {
//하고싶은것
} else {
//하고싶은것
}

타입스크립트에서의 조건문은 타 자바스크립트와 다르게 숫자나 문자가 올 수도 있습니다.
0이면 false 0이 아닌 값은 true로 들어오게 되고 빈 문자열이 오면 false 값이 있으면 true로 옵니다.
이러한 특징을 가지게 된 것은 JS의 특유한 if설정이 아닐까 생각합니다.
JS에서는 0, null, “”, undefined등의 값이 들어오면 if문에서 false로 보내버리는 특성을 가지고 있습니다.

예를 들어, 0 체크를 if로 한다면 JAVA에서는 if(변수 == 0) 이런 식으로 들어와야 하지만 JS에서는 if(변수)만 하면 체크가 됩니다.
참고 : is-there-a-standard-function-to-check-for-null-undefined-or-blank-variables-in

  • switch

자바스크립트나 타 언어의 switch와 같습니다.
특정 값일 경우 break를 만날때까지 계속 실행하는 식이죠.
모두 해당되지 않을 경우 마지막에 default를 만나면 실행되는 것 까지 같습니다.
보통 타입스크립트의 경우 하나의 변수에 대해 타입을 선언해 특정 타입만 받도록 쓰지만 모든 타입에 대해 받아서 switch문을 구성하고자 한다면 최상위 타입인 any를 통해 구현 가능합니다.

1
2
3
4
5
6
7
8
9
10
11
switch(command) {
case 값:
//하고싶은것
break;
case 값:
//하고싶은것
break;
default:
//하고싶은것
break;
}

noFallthroughCasesInSwitch 옵션을 걸어 break 관계없이 해당 구문에서 자동으로 탈출하도록 처리할 수 있지만 기본적으로 break를 꼭 넣도록 합시다.

타입스크립트의 반복문

타입스크립트에서도 ECMA스크립트의 발전에 맞춰 여러가지 반복문을 지원하고 있습니다.
여기서는 많이 아시는 for, while문에 대해 알아보겠습니다.

  • for

가장 기본적인 반복문에 대해 알아보겠습니다.

1
2
3
for (변수 초기화; 조건식; 증감식) {
하고싶은것;
}

ES5에서는 var만 지원하여 변수의 범위에 대해 생각하면서 작성해야 했지만 ES6에서 let(블록레벨 스코프)의 추가로 인해 그런 걱정이 많이 줄어들었으니 부담없이 치시면 되겠습니다.
타입스크립트에서의 사용법은 다음과 같습니다.

1
2
3
for(let i: number = 0; i < 2; i++;){
하고싶은것;
}
  • for … in

배열이나 객체를 순화할 때 사용하는 for문입니다.

배열순회의 예시 :

1
2
3
4
5
let islands = ["a","b","c"];

for (let index in islands){
console.log(index, islands[index]);
}

객체순회의 예시 :

1
2
3
4
5
let fruits = {"a":"apple", "b":"banana", "c":"cherry"};

for (let prop in fruits){
console.log(prop, fruits[property]);
}

배열을 순회할 때는 index에 숫자가 들어오지만 객체를 순회할 때는 키 값이 들어옵니다.

  • for … of

ES6에서 추가된 특징으로 객체[프로퍼티]를 써서 값을 가져왔던 for…in과 다르게 바로 값을 가져올 수 있는 특징을 가지고 있습니다.

1
2
3
4
5
let islands = ["a","b","c"];

for (let index of islands){
console.log(index, islands[index]);
}

이터러블(iterable, 반복가능)한 객체인 배열, 문자열, DOM, Map, Set등 에서 바로 값을 가져올 수 있습니다.
특정한 값이 변하지 않기 떄문에 const를 쓸 수도 있으며 호이스팅을 예방할 수도 있습니다.
for … of를 커스텀 객체에서 구현하고자 한다면 [Symbol.iterator]()를 구현하면 사용 가능합니다.

  • while

타 언어 처럼 조건문이 거짓일 때 까지 반복해서 실행합니다.
제 경험상 대부분 언제 끝날지 모르는 곳에서 많이 쓰였던 것 같습니다.
예를 들면, 소켓통신 수/송신 대기정도 있겠네요.

기본적인 사용법은 다음과 같습니다.

1
2
3
while(조건문){
하고싶은것;
}

예를 들어 하나만 작성해 본다면 다음과 같이 쓸 수 있습니다.

1
2
3
4
5
6
7
8
9
let count: number = 1;
let sum: number = 0;

while (count <= 100) {
sum += count;
count++;
}

console.log(sum);
  • do … while

while과 다르게 일단 한 번은 실행해본다는 특징이 있습니다.

1
2
3
do{
하고싶은것;
}while(조건문);

이상으로 반복문 정리를 마치겠습니다.

네티 알아보기 5일차 - 바이트 버퍼

바이트

말그대로 1바이트를 저장하는 변수입니다.

원래는 1바이트는 -128~127의 범위를 가지지만 통신 관련 작업할때는 부호가 없는 0~255까지의 범위에서 씁니다.

저 같은 경우는 통신할 때 써봤고 16진수로 변환하여 통신을 했습니다.

그 외에는 쓰일곳이 저 같은 초보에게는 많을 것 같지는 않습니다. 나중이라면 많이 쓸 수 있겠지만요.

java.nio.ByteBuffer

자바에서 바이트 데이터를 저장하고 읽을 수 있도록 바이트버퍼를 제공합니다.

실제 버퍼를 구현하기 위해 배열을 이용하고 있으며 배열의 인덱스에 접근하지 않아도 쉽게 작업할 수 있도록 여러 메소드를 제공합니다.

책에 따르면 버퍼의 상태를 관리하는 속성 세 가지를 제공하는데 다음과 같다고 합니다.

  • capacity : 버퍼에 저장할 수 있는 최대 크기로 한번 정하면 변경이 불가능하며 생성자의 인수로 입력한 값이다.
  • position : 읽기 또는 쓰기가 작업중인 위치를 나타내며 처음 생성시 0으로 초기화되고 position <= limit <= capacity의 범위를 가진다.
  • limit : 읽고 쓸 수 있는 버퍼 공간의 최대치를 나타내며 capacity 보다 크게 설정할 수 없다.

저 세개의 값으로 버퍼에서 읽고 쓰는데 도움을 주며 각각 속성의 사용법은 아래의 사진을 보고 참조하시면 좋을 것 같습니다.

index of stackoverflow

간단히 살펴보면 position과 limit로 어디까지 작업할지 선택하며 capacity로 오버플로우가 발생하지 않도록 체크하는 느낌입니다.

버퍼 만들기

자바에서 보통 객체 생성을 할 때는 new 생성자를 이용하지만 자바의 바이트 버퍼는 데이터 형에 따른 추상클래스 팩토리 메소도를 통해 생성합니다.

생성하는 메소드는 세 가지가 존재하며 다음과 같습니다.

  • allocate : JVM의 힙 영역에 바이트 버퍼를 생성합니다.
  • allocateDirect : JVM이 아닌 운영체제의 커널 영역에 바이트 버퍼를 생성합니다.
  • wrap : 입력된 바이트 배열을 사용하여 버퍼를 생성합니다. 말그대로 일반 바이트 배열을 버퍼로 wrap해주는 용도라 보시면 될 것 같습니다.

보통 다이렉트 버퍼가 힙에 생성된 버퍼에 비해 생성 시간은 길지만 빠른 성능을 제공합니다.
“어 다이렉트 짱이네!” 하고 많이 생성하시면 곤란합니다.
JVM의 관리하에 있으니 컨트롤도 완벽하지 않을 수도 있고, 운영체제에 부담을 줄 수도 있고 등등등….(제 생각)

기본적인 생성 방법은 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class javaBufSample {

public void createTest() {
ByteBuffer heapBuffer = ByteBuffer.allocate(3);
ByteBuffer directBuffer = ByteBuffer.allocateDirect(3);
byte[] testArray = {0x01, 0x02, 0x03};
ByteBuffer wrapBuffer = ByteBuffer.wrap(testArray);

System.out.println(heapBuffer.isDirect()); //false
System.out.println(directBuffer.isDirect()); //true
System.out.println(heapBuffer.isDirect()); //false
}
}

실행해 보시면 다이렉트 버퍼만 true고 나머지는 false로 되어있는 것을 볼 수 있습니다.
즉, wrap메소드의 처리결과로 봐서 직접적으로 명시하지 않는 이상 JVM의 영역을 기본적으로 사용한다는 것을 확인할 수 있습니다. 사실 당연한거죠..

보통 문자열이나 숫자등의 처리를 위해 byte형으로 변경할 수 있도록 메소드를 제공하고 있습니다.
그리고 선언한 버퍼의 크기보다 많으면 java.nio.BufferOverflowException이 발생합니다.

flip 메소드

하나의 바이트 버퍼가 쓰고 있다고 가정해봅시다. 쓰기 모드에서 버퍼에 데이터를 기록하면 position은 데이터의 가장 마지막을, limit는 버퍼의 가장 마지막을 가리키고 있을 것입니다.
이 버퍼에서 지금까지 작성한 데이터를 읽고 싶다면 예제야 0~position까지 읽으면 되겠지만 실제에서는 어떻게 되있을지 모르며 0부터 읽을 수 있을지 없을지도 모릅니다.
그래서 자바에서는 읽기에서 쓰기모드를 변환시켜주는 filp 메소드를 제공합니다.
이 메소드를 사용하면 버퍼에 존재한 데이터를 바탕으로 속성들의 위치를 변경시켜줍니다.

즉, 위의 그림에서 왼쪽에서 오른쪽으로 변경해 데이터를 안전하게 읽으려면 filp 메소드가 필요한 것이죠.
이러한 특성때문에 다중 스레드환경이나 읽기/쓰기를 분리해야 하는 등 불편한 사항이 많다고 합니다.

io.netty.buffer.ByteBuf

Netty 바이트 버퍼는 자바 바이트 버퍼보다 더 빠른 성능을 제공하며 버퍼 풀 등 여러가지 기능을 많이 가지고 있습니다. 이 바이트 버퍼가 가진 특징은 다음과 같습니다.

  • 별도의 읽기/쓰기 인덱스 존재
  • filp 메소드 없이 읽기/쓰기 가능
  • 가변 바이트 버퍼
  • 바이트 버퍼 풀
  • 복합 버퍼
  • 자바의 바이트 버퍼와 상호 변환 가능

이러한 바이트 버퍼를 따로 사용할 수 있도록 버퍼만 따로 클래스로 제공하기도 하니 필요하시면 가져다가 쓰시면 되겠습니다.
그리고 자바의 경우 intBuffer 등의 자료형마다 따로 버퍼클래스를 제공하지만 Netty 에서는 readInt/writeInt등의 자료형별로 메소드를 따로 제공하여 사용합니다.

사용해보기

먼저 Netty 바이트 버퍼를 생성할 때 풀링 여부 / 다이렉트 여부 두 가지를 선택해야 합니다.
그래서 이 기능에 따라 생성 가능한 버퍼 종류는 네가지입니다.

  • PooledHeapByteBuf
  • PooledDirectByteBuf
  • UnPooledHeapByteBuf
  • UnPooledDirectByteBuf

자바에서 추상 클래스의 팩토리 메소드를 사용해 생성했듯이 Netty도 클래스의 생성자가 아닌 메소드를 사용하여 생성합니다.
한 번 만들어 보겠습니다.

1
2
3
4
5
6
7
8
public class NettyBufSmaple {
public void createTest(){
ByteBuf PooledHeapByteBuf = PooledByteBufAllocator.DEFAULT.heapBuffer();
ByteBuf PooledDirectByteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
ByteBuf UnPooledHeapByteBuf = Unpooled.buffer();
ByteBuf UnPooledDirectByteBuf = Unpooled.directBuffer();
}
}

변수명을 보시면 어떻게 만들 수 있는지 보실 수 있습니다. 크기의 경우 메소드에 인자로 넣어주시면 크기가 지정 가능합니다.

그 외 특징으로는 capacity로 쉽게 크기 변경이 가능하며 readIndex/writeIndex의 분리로 인해 쉽게 읽고 쓰는 작업이 가능합니다.

바이트 버퍼 풀링

Netty의 가장 중요한 특징은 바이트 버퍼 풀링입니다.
객체 생성 등의 비용을 최대한으로 줄이기 위해 풀링 방법을 사용하며 다이렉트/힙 버퍼에 대해 모두 사용할 수 있습니다.
이러한 풀링으로 인해 GC에 부담을 적게 주며 메모리를 다른 곳에 더 사용할 수 있도록 합니다.

ReferenceCountUtil 클래스에 정의된 retain/release 메소드를 사용하여 풀링의 크기를 관리할 수 있습니다.

C언어와 같이 변수에 부호가 없는 경우 Netty는 한단계 더 큰 데이터형에 저장합니다.
예를 들면, getUnsignedInt 메소드를 호출 할 경우 int->long으로 업그레이드 해서 반환하는 식입니다.

자바 -> Netty 간 바이트버퍼 상호 변환을 위해 nioByteBuffer 메소드를 제공합니다.
Netty -> 자바에서는 wrappedBuffer 메소드를 사용하시면 됩니다.

마무리

간단하게 바이트 버퍼에 대해 살펴봤습니다.
책에도 써있는 말 인데 자바 바이트 버퍼로 Netty를 사용하여 통신이 가능하지만 굳이 그럴 필요는 없겠죠.
특히 filp 메소드를 호출하지 않아도 되니까 버그 발생률을 줄여 정시퇴근이 가능할수도 안할수도 있습니다.

타입스크립트 1 - 소개, 설치, 변수

책 : 타입스크립트 퀵스타트

ECMA스크립트 이론

ECMA = 유럽 컴퓨터 제조사 연합의 약자로 스크립트의 표준을 만들고 관리하는 단체로 스크립트 외 C#이나 다트 등의 언어표준과 JSON, XML등의 데이터 교환 표준도 관리하고 있습니다.

ECMA 스크립트 발전연도

  • 1997 : ES1
  • 1998 : ES2
  • 1999 : ES3
  • 2008 : ES4
  • 2009 : ES5
  • 2013 : ES6(ES2015)
  • 2016 : ES7(ES2016)
  • 2017 : ES8(ES2017)
  • 2018 : ES9(ES2018)

타입스크립트

MS에서 개발하고 관리하는 오픈소스 프로그래밍 언어로 브라우저, OS등에 상관없이 동작합니다.
자바스크립트의 상위 호환으로 ECMA스크립트의 최신 표준을 지원하며 자바스크립트를 보완해 변수나 함수 등에 명시적으로 타입을 명시해 안전성을 높이고 모듈화, 객체지향등 최신 트렌드도 충분히 따를 수 있도록 합니다.

역사

자바스크립트는 대규모 어플리케이션을 개발하는 데 있어 불편하다는 불만에 대응하기 위한 목적으로 발명되었습니다.
델파이의 창시자이자 C# 언어의 설계를 맡고 있는 앤더스 헤일스버그라는 사람이 이끌고 있습니다. 그 외 난다긴다하는 수많은 사람들이 함께하고 있습니다.

2012년 10월에 첫 출시되어 ECMA스크립트 발표 주기에 맞춰 빠르게 업데이트하면서 최신으로 항상 유지하고 있으며 2014년에 타입스크립트 만을 위한 컴파일러가 등장했으며 2.x부터 서드파티 라이브러리를 쉽게 사용할 수 있도록 개선되어졌습니다.
그리고 자바스크립트의 보완 도구로써뿐 아니라 개발을 지원하는 각종 환경(컴파일러 타입 검사, ES5, ES3 하위호환성 등)도 계속 지원하고 있습니다.

특징

동적 언어인 자바스크립트와 달리 정적 언어기 때문에 시간은 들지만 안전성을 보장합니다.
정확히 말하면 타입 안전성을 갖는 타입스크립트를 컴파일하면 자바스크립트로 변화하기 때문에 안전성과 속도 두 가지를 전부 잡았다고 볼 수 있습니다.
즉, 자바스크립트를 완전히 대체할 수는 없으나 보완하는 역할로 쓰고 있습니다.

TypeScript = JavaScript + Type

확장된 자바스크립트로써 모듈화, 객체지향, 구조화등 대규모 어플리케이션을 만들 수 있도록 여러가지를 갖추고 있습니다.

  • 모듈과 네임스페이스 지원

모듈을 선언하거나 호출할 수 있도록 하는 방식을 지원합니다.
변수 -> 함수 -> 클래스로 원하는 크기에 맞춰 사용할 수 있으며 영역 구분을 위해 네임스페이스를 지원합니다.

  • 클래스와 인터페이스 지원

ES6의 클래스 기능에 덧붙여 인터페이스를 지원하으로써 객체지향 프로그래밍 환경을 제공합니다.
이러한 특징으로 인해 평소 익숙한 자바나 C#등과 같은방식으로 프로그래밍 할 수 있습니다.(interface, implements, extends …)

기존 언어와 차이점은 다음과 같습니다.

  • ES6에 없던 인터페이스를 지원합니다.
  • 자바는 다중 생성자를 선언할 수 있지만 타입스크립트는 하나만 지원합니다.
  • 타입스크립트는 자바와 달리 디폴트 초기화 매개변수와 선택 매개변수를 선언할 수 있습니다.
  • 타입 시스템 지원

실행시 변수 타입이 선언되던 JS와 달리 엄격한 타입을 지정하여 특정한 타입만 받을 수 있도록 합니다.
string으로 선언하면 무조건 string만 받을 수 있습니다.

만약 string으로 컴파일하게 되면 타입검사 -> 어노테이션 제거 -> 자바스크립트 변수로 출력하는 과정을 거치게 됩니다. 그리고 변수가 의도한 타입이 아닐 경우 이를 체크하기 위해 필요했던 루틴을 제거하여 성능이나 코드상의 이득을 볼 수 있습니다.

아키텍처

언어를 좀 더 이해하려면 아키텍처를 볼 필요가 있다고 합니다. 전체 아키텍처는 다음과 같습니다.

Architectural overview.

  • 코어 타입스크립트 컴파일러

타입스크립트 아키텍처는 언어 변환 기능을 수행하는 코어 타입스크립트 컴파일러를 기반으로 합니다.

이 컴파일러는 파서, 바인더, 타입체커, 에미터, 전처리기로 구성되어 있습니다.

  • 파서 : 소스코드를 해석해 구문 트리를 만들고 이걸 해석해 중복 내용을 제거한 추상 구문트리를 만듭니다.
  • 바인더 : 인터페이스나 모듈등에 선언이 있을 때 이러한 선언을 심벌(symbol)로 보고 규칙을 정의합니다.
  • 타입 체커 : 타입이 적절한지 체크하고 구문을 분석합니다.
  • 에미터 : .ts -> .js, .d.ts, .js.map
  • 전처리기 : 파일에 선언된 import문이나 <reference path=경로>등의 외부 호출 선언이 있을 때 파일을 가져와 파일목록을 생성합니다. 즉, 컴파일러는 전처리기에서 가져온 파일을 이용해 컴파일을 수행합니다.
  • 언어 서비스

코드를 컴파일해서 편집기에서 필요한 기능을 제공합니다.

  • 독립 서버

컴파일러와 언어 서비스 같은 하위 레이어를 래핑해서 JSON 형식을 통해 외부에 정보를 노출할 수 있게 합니다.
tsserver로 불리며 응용 개발에서는 직접 다룰일이 없으며 플러그인을 개발할 때 사용할 수 있습니다.

  • 편집기

하위 레이어의 요소를 모두 고려해 동작하는 최종 응용 단계의 어플리케이션입니다.

  • 컴파일러
  • 컴파일링 : 한 언어의 소스코드를 다른 언어로 바꾸는 것
  • 트랜스파일링 : 한 언어의 소스코드를 비슷한 추상화 수준의 다른 언어로 바꾸는 것

타입스크립트의 경우 자바스크립트로 바꾸니까 컴파일이라고도 할 수 있지만 같은 추상화 수준의 자바스크립트로도 바꾸기 때문에 트랜스파일링이라고도 할 수 있습니다.
대부분 많이 쓰는 언어인 컴파일러를 주로 사용하는 편입니다.

호출자는 tsc를 호출하여 사용할 수 있습니다.

설치

먼저 node.js를 능력껏 설치합니다.

그리고 콘솔창을 출력해서 다음과 같이 입력합니다.

1
npm install -g typescript

버전확인은 다음과 같이 합니다.

1
tsc -v

업데이트는 npm을 사용해 다음과 같이 설치합니다.

1
npm outdated -g typescript

타입스크립트의 확장자는 .ts이며 컴파일은 다음과 같이 진행합니다.

1
tsc 파일명.ts

컴파일하면 js파일이 생성되기 때문에 실행의 경우 node 파일명.js로 하시면 됩니다.

만약, 바벨을 이용한 하위 스크립트로 변환하기 위해서는 다음과 같이 사용합니다.

1
tsc 파일명.ts -t 버전명

버전명에는 ES3, 5, 6, 2016, 2017, Next(항상최신버전)등을 사용할 수 있습니다. 기본값은 ES3 입니다.

tsconfig.json

프로젝트가 커지다 보면 어떤 특징을 이용해 컴파일하는지 각종 설정 등 복잡해 지는 경우가 많습니다.
그래서 tsconfig.json을 사용하여 보관하면 편하게 컴파일 할 수 있습니다.

중요한점은 tsconfig.json이 있는 폴더가 루트폴더가 되기 때문에 경로 설정에 주의하도록 합니다.
초기 파일생성은 tsc --init으로 간단하게 만들 수 있습니다. 만들게 되면 몇가지 옵션이 보이는데 책에 나와 있는 옵션은 다음과 같습니다.

  • sourceMap : 컴파일 후 맵파일의 생성여부 설정
  • strict : 엄격 타입 검사 모드 설정
  • noImplicitAny : any 타입으로 암묵적 형변환 여부를 결정
  • esModuleInterop : ECMA스크립트 모듈과 상호 운용성을 가능하게 하는 속성으로 true면 CommonJS모듈을 디폴트 처럼 호출할 수 있습니다.

나머지는 Docs를 찾아봅시다..

변수와 기본타입

변수

js의 변수와 같이 사용합니다. 타입스크립트에서 추가된 것은 뒤에 타입이 붙습니다.
기본적으로 JS의 변수이기 때문에 기본적인 정리는 아래의 블로그에서 한번 보시면 좋을 것 같습니다.

블로그 가기

타입스크립트에서의 사용법은 다음과 같습니다 :

1
var(let,const) 변수명: 타입명 = '값';

예를 들면 let myNickName: string = 'happy';와 같이 쓰면 되겠습니다.

타입스크립트에서 지원하는 타입은 기본, 객체, 기타 타입을 지원합니다.
기본 타입의 경우 string, number ,boolean, symbol, enum, 문자열 리터럴이 존재합니다.
객체 타입의 경우 Array, Tuple, Function, Constructor(생성자), Class, Interface가 존재합니다.
기타 타입의 경우 union, intersection 등이 존재합니다.

위의 타입 외 변형된 타입도 존재하며 나중에 배울 것입니다.

기본타입

자바스크립트타입 포함 여러 가지 타입을 지원합니다.

  • Symbol

ES6에서 추가된 기능으로써 객체 속성(프로퍼티)의 유일한 식별자로 사용됩니다.
symbol 값이 정의되면 고유한 값으로 취급됩니다.

1
2
3
4
let sym2 = Symbol("key");
let sym3 = Symbol("key");

sym2 === sym3; // false, symbols are unique
  • enum

자바나 C#의 enum과 비슷합니다. 초기값으로 타입스크립트 2.4부터는 문자열도 할당이 가능합니다.

  • any, object

제약이 없는 타입으로 어떤 타입의 값도 받을 수 있습니다. 그래서 타입의 결과를 예측할 수 없을 때 사용하면 유연한 대응을 할 수 있습니다.
자바나 C#의 object와 같다고 보시면 되겠습니다.

JS의 Object는 컴파일 시점에 속성의 유무를 검사하지만 any 타입은 런타임 시점에 검사합니다.

반드시 타입을 지정해야 한다면 noImplicitAny를 true로 선언하여 암묵적 형변환을 방지할 수 있습니다.

  • array

JS에서 기본적으로 사용하는 배열입니다. let fruits: string[]으로 사용하며 any가 와서 모든 타입을 받을 수 있습니다만 조금 제약하려면 number | string | boolean같은 유니언 타입으로 제약을 할 수 있습니다.

  • Generic

Array의 형식으로 선언하며 나중에 좀 더 자세히 배울것입니다.
배열과 달리 내장 타입 외 객체타입도 받을 수 있습니다. 배열 요소로 익명함수를 받으려면 람다식을 사용해 편하게 let nums: Array<() => string> 같은 방식으로 받을 수 있습니다.

  • Tuple

n개의 요소가 이뤄진 배열에 대응하는 타입을 의미합니다. 특정 n개에 대해 타입을 강제할 수 있으며 간단히 예를 들어 보겠습니다.

1
let a : [string, number]=["tuple", number, 문자나 숫자...]

대충 이런 식이 있다고 했을 때 우측 값배열의 첫 번째는 튜플의 첫 번째 타입인 string, 다음 두 번째는 튜플의 두 번째 타입인 number를 받고, 그 이후에 들어오는 값은 string과 number 중 아무거나 다 받게 됩니다.

그리고 2.7 이후로 선언한 튜플의 타입 갯수와 우측 값 배열의 타입 갯수가 일치해야 선언되도록 변경되었습니다.

  • void, null, undefined

함수의 반환값이 없을 때 void나 undefined를 받을 수 있습니다. 그렇다고 변수가 값이 할당되지 않을 떄를 나타내기 위하여 null은 권장하지 않습니다.
이러한 불안정한 연산을 막기 위해 tsconfig.json에서 strictNullChecks 옵션을 true로 설정해 막을 수 있습니다.

undefined의 경우는 초기화 되지 않았음을 의미하지만 null은 null 자체로 하나의 값이기 때문에 신중해서 사용할 필요가 있습니다.

  • never

예외를 던지거나 결과값을 리턴할 수 없는 타입입니다.

  • interface, class, Constructor

객체지향 프로그래밍에서 쓰이는 용도와 유사하게 사용합니다.
예제코드를 보시면 쉽게 이해가능하실것 같습니다 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//디폴트 인터페이스
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick();
}

//파라미터의 생성자로 인터페이스를 받고 다른 인터페이스를 구현함
function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
return new ctor(hour, minute);
}

//tick은 ClockInterface에서 정의한 tick
class DigitalClock implements ClockInterface {
constructor(h: number, m: number) { }
tick() {
console.log("beep beep");
}
}

class AnalogClock implements ClockInterface {
constructor(h: number, m: number) { }
tick() {
console.log("tick tock");
}
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);
  • union

두 가지의 타입을 합쳐서 하나로 사용할 수 있게 만든 타입입니다.
| 문자를 사용해 정의합니다.
아래 예제의 val은 stringnumber를 동시에 사용할 수 있도록 정의한 예제입니다.

1
2
3
4
5
var val:string|number 
val = 12
console.log("numeric value of val "+val)
val = "This is a string"
console.log("string value of val "+val)
  • intersection

union이 변수에 대한 합치기라면 intersection은 객체에 대한 합치기입니다.
& 문자를 사용하며 아래 예제를 보시면 쉽게 이해 가능하실겁니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
interface IStudent {
id: string;
age: number;
}

interface IWorker {
companyId: string;
}

//뒤의 값은 인터페이스의 생성자
let x: A = {age : 5, companyId : 'CID5241', id : 'ID3241'};

console.log(x);

이상으로 3장 변수까지 마치겠습니다.