Million Dreams
100만개의 꿈을 꾸는 개발자 지망생
TypeScript (2)
Do it! 타입스크립트 프로그래밍 5장

Ch05 배열과 튜플

5-1) 배열 이해하기

- 자바스크립트에서 배열은 Array 클래스의 인스턴스이며 다음처럼 선언함

let 배열 이름 = new Array(배열 길이)

let array = new Array

array.push(1); array.push(2); array.push(3)

console.log(array)

 

- 배열에 담긴 각각의 값을 아이템(item) 또는 원소(element)라고 하며, 위의 예제 배열에는 3개의 아이템을 담고 있다.

 

(1) [ ] 단축 구문

- 자바스크립트는 [ ] 단축 구문을 제공하며, 이를 이용해 한번에 배열을 만들 수도 있다.

let numbers = [123]

let strings = ['Hello''World']

console.log(numbersstrings)

 

(2) 자바스크립트에서 배열은 객체다

- 자바스크립트에서 배열은 다른 언어와 다르게 객체임. Array클래스의 인스턴스이기 때문

- Array클래스에서 제공하는 여러 메서드 중 Array.isArray는 매개변수로 전달받은 심벌이 배열인지 객체인지 알려줌

 

(3) 배열의 타입

- 타입스크립트에서 배열의 타입은 아이템 타입[]’.

let numArray: number[] = [123]

let strArray: string[] = ['Hello''World']

 

type IPerson = {name: stringage?: number}

let personArray: IPerson[] = [{name: 'Jack'}, {name: 'Jane', age: 32}]

 

 

(4) 문자열과 배열 간 변환

- 어떤 프로그래밍 언어는 문자열(string)을 문자(character)들의 배열(array)로 간주하지만 타입스크립트에선 문자 타입이 없고 문자열의 내용 또한 변경할 수 없다.

- 문자열을 가공하려면 문자열을 배열로 전환해야함 (Stringsplit 클래스 이용)

split(구분자: string): string[]

export const split = (str: stringdelim: string = ''): string[] => str.split(delim)

 

split 함수는 매개변수로 전달받은 문자열과 구분자를 이용해 String 클래스의 split 메서드를 호출함으로써 string[] 타입의 배열로 만들어줌

import {splitfrom './split'

console.log(

    split('hello'),

    split('h_e_l_l_o''_')

)

 

[ 'h', 'e', 'l', 'l', 'o' ] [ 'h', 'e', 'l', 'l', 'o' ]

 

 

- string[] 타입의 배열을 다시 string으로 변환하려면 Array 클래스의 join 메서드를 사용

join(구분지: string): string

 

(5) 인덱스 연산자

- 배열이 담고 있는 아이템 중 특정 위치에 있는 아이템을 얻고자 할 때는 인덱스 연산자(index operator)[인덱스]를 사용

const numbers: number[] = [12345]

for(let index = 0index < numbers.length; index++) {

    const item: number = numbers[index]

    console.log(item)

}

 

(6) 배열의 비구조화 할당

- 객체뿐 아니라 배열에도 비구조화 할당을 적용할 수 있음. 배열의 비구조화 할당문에는 [] 기호 사용

 

(7) for … in

- ESNext 자바스크립트와 타입스크립트는 for 문을 좀 더 쉽게 사용하도록 for…in 문을 제공

for(변수 in 객체) {

}

let names = ['Jack''Jane''Steve']

 

for (let index in names) {

    const name = names[index]

    console.log(`[${index}]: ${name}`)

}

 

[0]: Jack

[1]: Jane

[2]: Steve

 

- 만약 for…in문에 객체를 사용할 때는 객체가 가진 속성을 대상으로 순회함

let jack = {name: 'Jack', age: 32}

for(let property in jack)

console.log(`${property}: ${jack[property]}`)

 

name: Jack

age: 32

 

(8) for…of

- for…in문이 배열의 인덱스 값으로 대상을 순화한다면, for…of는 배열의 아이템값을 대상으로 순회함

for(let name of ['Jack''Jane''Steve'])

    console.log(name)

 

(9) 제네릭 방식 타입

- 배열을 다루는 함수 작성시 number[]처럼 타입이 고정된 함수가 아닌 T[]처럼 배열의 아이템 타입을 한꺼번에 표현하는 것이 편리함

- 타입을 T와 같이 일종의 변수(타입 변수)로 취급하는 것을 제네릭(generics)타입이라고 함

 

Ex) 예를 들어 배열의 길이를 얻는 함수로 arrayLength를 선언한다면 다음과 같이 만들 수 있음

const arrayLength = (array) => array.length

 

이를 다양한 아이템 타입을 가지는 배열에 똑같이 적용하려면 다음과 같이 표현 가능

const arrayLength = (array: T[]): number => array.length

 

그러나 이러면 컴파일러에게 T가 타입 변수라고 알려줘야 함으로 다음과 같이 표현한다.

const arrayLength = <T>(array: T[]): number => array.length

 

배열이 비어있는지 확인함수는 다음과 같이 표현 가능하다

export const isEmpty = <T>(array: T[]): boolean => arrayLength<T>(array== 0

 

Ex) import {arrayLengthisEmptyfrom './arrayLength'

let numArray: number[] = [123]

let strArray: string[] = ['Hello''World']

 

type IPerson = {name: stringage?: number}

let personArray: IPerson[] = [{name: 'Jack'}, {name: 'Jane', age: 32}]

 

console.log(

 

    arrayLength(numArray),

    arrayLength(strArray),

    arrayLength(personArray),

    isEmpty([]),

    isEmpty([1])

)

 

Result: 3 2 2 true false

 

(10)제네릭 함수의 타입 추론

제네릭 형태로 구현된 함수는 원칙적으로 다음과 같이 명시해주어야함

함수 이름<타입 변수>(매개변수)

그러나 타입스크립트는 다음 예시(4)처럼 타입 변수 부분을 생략할 수 있게함.

const identity = <T>(n: T): T => n

console.log(

    identity<boolean>(true),

    identity(true)

)

 

이 경우, 타입스크립트는 타입 추론을 통해 생략된 타입을 찾아냄

(11) 제네릭 함수의 함수 시그니처

- const f = <T>(cb: (arg: T, i?: number) => number): void => {}

다음과 같은 형태로 변수를 삽입해서 변수에 타입을 명시해 해결함

 

(12) 전개 연산자

- 배열에도 전개연산자 적용이 가능ㅎ며, 예시처럼 전개 연산자를 사용해 두 배열과 특정 값을 동시에 결합할 수 있다.

 

(13) range 함수 구현

- 배열에 전개 연산자를 적용하면 ramda 외부 패키지가 제공하는 R.range와 같은 방식으로 range 함수를 구현할 수 있다.

export const range = (from: numberto: number): number[] =>

    from < to ? [from...range(from + 1to)] : []

 

import {rangefrom './range'

let numbers: number[] = range(19 + 1)

console.log(numbers)

 

 

 

 

 

 

 

 

 

 

 

 

5-3) 배열의 map, reduce, filter 메서드

(1) filter 메서드

- 배열의 타입이 T[]일 때 배열의 filter 메서드는 다음과 같은 형태로 설계되었음

Filter(callback: (value: T, index?: number): boolean ): T[]

Filter method의 사용 예

import {rangefrom '../../ch05-1/src/range'

 

const array: number[] = range(110+1)

 

let odds: number[] = array.filter((value) => value % 2 != 0)

let evens: number[] = array.filter((value) => value % 2 == 0)

console.log(oddsevens)

 

 

- filter 메서드는 두번째 매개변수에 index라는 선택 속성을 제공

index값을 사용해 배열을 반(half)으로 나눈 예

import {rangefrom '../../ch05-1/src/range'

 

const array: number[] = range(110+1)

const half = array.length / 2

 

let belowHalf: number[] = array.filter((vindex) => index < half)

let overHalf: number[] = array.filter((vindex) => index >= half)

console.log(belowHalfoverHalf)

 

(2) map 메서드

- 배열의 타입이 T[] 일 때 배열의 map 메서드는 다음과 같은 형태로 설계되며 filter와 달리 map 메서드는 입력 타입과 다른 타입의 배열을 만들 수 있음

Map(callback: (value: T, index?: number): Q): Q[]

 

Map을 사용해 Number[] 타입 배열을 string[] 타입배열로 가공한 예

import {rangefrom '../../ch05-1/src/range'

 

let names: string[] = range(15 + 1)

    .map((valindex) => `[${index}]: ${val}`)

console.log(names)

 

(3) reduce 메서드

- reduce함수는 다음과 같이 설계됨

Reduce(callback: (result: T, value: T), initialValue: T): T

 

1부터 100까지 더하는 로직을 reduce메소드를 사용해 구현한 예

import {rangefrom './range'

 

let reduceSum: number = range(1100 + 1)

    .reduce((result: numbervalue: number) => result + value0)

console.log(reduceSum)

 

 

5-4) 순수 함수와 배열

- 함수형 프로그래밍에서 함수는 순수 함수(pure function)’라는 조건을 만족해야 함. 그러나 타입스크립트의 Array 클래스에는 순수 함수 조건에 부합하지 않는 메서드가 많음

- 순수 함수란 부수 효과(side-effect)가 없는 함수를 말하는데, 부수 효과란 함수가 가진 고유 목적 이외에 다른 효과가 나타나는 것을 말하며 부작용이라고도 함

- 이러한 부수 효과가 있는 함수는 불순 함수(impure function)이라고 함

- 순수 함수과 되려면 다음과 같은 조건을 만족해야 함

순수 함수의 조건

함수 몸통에 입출력 관련 코드가 없어야한다.

함수 몸통에서 매개변숫값을 변경시키지 않는다.(, 매개변수는 constreadonly 형태로만 사용한다.)

함수는 몸통에서 만들어진 결과를 즉시 반환한다.

함수 내부에 전역 변수나 정적 변수를 사용하지 않는다.

함수가 예외를 발생시키지 않는다.

함수가 콜백 함수로 구현되었거나 함수 몸통에 콜백 함수를 사용하는 코드가 없다.

함수 몸통에 Promise와 같은 비동기 방식으로 동작하는 코드가 없다.

 

순수 함수의 예

Function pure(a: number, b:number): number {return a + b}

 

불순 함수의 예

function impure(array: number[]): void {

array.push(1)

array.splice(0, 1)

}

 

(1) 타입 수정자 readonly

- 타입스크립트는 순수 함수 구현을 위해 readonly 키워드를 제공하며 readonly 타입으로 선언된 매개변숫값을 변경하려면 경고창을 띄워 불순함수가 되는 것을 막는다.

 

(2) 불변과 가변

- constreadonly를 명시하고 있으면 변숫값은 초깃값을 항상 유지하며 이를 불변(immutable) 변수라고 함

 

- 반면 let이나 readonly를 명시하지 않는 변수는 값 변경이 가능하므로 가변(mutable) 변수라고 함

 

(3) 깊은 복사와 얕은 복사

- 프로그래밍 언어에서 어떤 변숫값을 다른 변숫값으로 설정하는 것을 복사(copy)라고 표현하며 복사에는 깊은 복사(deep-copy)’, ‘얕은 복사(shallow-copy)’ 두 종류가 있음

- 순수 함수 구현시에는 매개변수가 불변성을 유지해야하므로, 깊은 복사를 실행해 매개변숫값이 변경되지 않도록 해야함

- 깊은 복사는 대상 변숫값이 바뀔 때 원본 변숫값은 그대로인 형태로 동작

깊은 복사의 예

let original = 1

let copied = original

copied += 2

console.log(originalcopied)

 

결괏값: 1 3

 

- 객체와 배열은 얕은 복사 방식으로 동작함

얕은 복사의 예

const originalArray = [5397]

const shallowCopiedArray = originalArray

shallowCopiedArray[0= 0

console.log(originalArrayshallowCopiedArray)

 

결괏값: [ 0, 3, 9, 7 ] [ 0, 3, 9, 7 ]

 

(4) 전개 연산자와 깊은 복사

- 전개 연산자를 사용해 배열을 복사하면 깊은 복사를 할 수 있음

전개 연산자를 사용해 깊은 복사를 한 예

const oArray = [1234]

const deepCopiedArray = [...oArray]

deepCopiedArray[0= 0

console.log(oArraydeepCopiedArray)

 

결괏값: [ 1, 2, 3, 4 ] [ 0, 2, 3, 4 ]

 

(5) 배열의 sort 메서드를 순수 함수로 구현하기

- Array 클래스의 sort메서드는 배열의 아이템을 오름차순(ascend) 또는 내림차순(descend)로 정렬해줌

 

- , sort 메서드는 원본 배열의 내용을 변경하므로 readonly 타입을 적용해 순수함수로써 sort 역할을 하는 메서드를 만들어 봄

export const puerSort = <T>(array: readonly T[]): T[] => {

    let deepCopied = [...array]

    return deepCopied.sort()

}

 

pureSort의 사용 예

import {pureSortfrom './pureSort'

 

let beforeSort = [ 629 ,0]

const afterSort = pureSort(beforeSort)

console.log(beforeSortafterSort)

결괏값: [ 6, 2, 9, 0 ] [ 0, 2, 6, 9 ]

 

(6) 배열의 filter 메서드와 순수한 삭제

- 배열에서 특정 아이템을 삭제할 때는 slice 메서드를 사용하지만, 원본 배열의 내용을 변경하므로 순수 함수에서는 사용 불가함

 

- 대신 filter 메서드를 사용할 수 있음. 배열이 제공하는 filtermap 메서드는 sort와 달리 깊은 복사 형태로 동작하므로 filter 사용하면 원본 배열의 내영을 훼손하지 않으면서 조건에 맞지 않는 아이템을 삭제 가능함

 

filter 사용해 특정 아이템을 삭제하는 함수 예

export const pureDelete = <T>(array: readonly T[], cb: (val: Tindex?: number) => 

boolean): T[] => array.filter((valindex) => cb(valindex== false)

 

배열과 객체가 섞인 원본을 훼손하지 않으면서 배열만 제거한 배열(objectOnly)를 만든 예

import {pureDeletefrom './pureDelete'

 

const mixedArray: object[] = [

    [], {name:'Jack'}, {name: 'Jane', age: 32}, ['description']

]

const objectOnly: object[] = pureDelete(mixedArray(val) => Array.isArray(val))

console.log(mixedArrayobjectOnly)

 

(7) 가변 인수 함수와 순수 함수

- 함수를 호출할 때 전달 인수의 개수를 제한하지 않는 것을 가변 인수(variadic arguments)라고 하며 매개변수 앞의 은 잔여나 전개 연산자가 아니라 가변 인수를 표현하는 구문임

 

5-5) 튜플 이해하기

- 파이썬 등에는 튜플이 존재하지만, 자바스크립트에서는 튜플이 없으며 단순히 배열의 한 종류로 취급됨.

let tuple: any[] = [true'the result is ok']

 

- 그러나 any[] 형태는 타입 기능을 무력하므로 다르게 선언할 수 있음

const array: number[] = [123 ,4]

const tuple: [booleanstring= [true'the result is ok']

 

(1) 튜플에 타입 별칭 사용하기

- 일반적으로 튜플 사용시에는 타입 별칭(alias)로 튜플의 의미를 명확하게 함

 

  Comments,     Trackbacks
Do it! 타입스크립트 프로그래밍 1장

 

Chap01 타입스크립트와 개발 환경 만들기

1-1 타입스크립트란 무엇인가?

 

1) 세종류의 자바스크립트

- ES5(ECMAScript 5) : 웹 브라우저에서 동작하는 표준자바스크립트

 

- ESNext : 2015년부터 매년 새로운 버전을 발표하는 ESNext ES6를 포함해 ES6이후의버전들을 ESNext라고 부르기 시작했다. ES6부터는 발표연도를 붙여 ECMAScript 2015처럼 부르기로 함. 이를통들어서 ESNext라고 하며 현재는 ECMAScript 2019까지나온 상황

 

- TypeScript : ESNext의 모든 문법을 포함하되, ESNext에 타입 기능을 추가한 스크립트

 

2) 타입스크립트는 누가 만들었나?

- 마이크로소프트가 개발하고 유지하고 있는 오픈 소스 프로그래밍언어 (2012년말 발표)

 

- C# 언어를 차이샇ㄴ 아네르스 하일스베르가 핵심 개발자로 참여중

 

3) 트랜스파일

- ESNext 자바스크립트 소스코드는 바벨(Babel)이라는 트랜스파일러(transpiler)를 거치면 ES5 자바스크립트 코드로 변환되며, 타입스크립트 소스코드는 TSC(TypeScript compiler)라는 트랜스파일러를 통해 ES5 자바스크립트코드로 변환됨

 

- 트랜스파일러란, 어떤프로그래밍 언어로 작성된 소스코드를 또 다른 프로그래밍 언어로 된 소스코드로 바꿔주는 프로그램을 말함.

 

- 텍스트로 된 소스코드를 바이너리 코드로 바꿔주는 컴파일러와 구분해서사용

 

1-2 타입스크립트 주요 문법 살펴보기

1) ESNext의 주요 문법

(1) 비구조화 할당

- 비구조화 할당을 통해 각 멤버의 요소를 쉽게 분리해서 얻을 수있다.

 

(2) 화살표 함수

- 자바스크립트에서 함수를 선언할 때는 다음 코드의 01행처럼 function 키워드를 사용하지만, ESNext에서는 function 키워드 외에오 화살표(=>)로 함수 선언이 가능

 

(3) 클래스

- ESNext에서는 클래스 기능을 지원해 C++ Java 언어에서 보던 객체지향 프로그래밍을 지원한다. 캡슐화, 상속, 다형성이라는 세가지 요소 지원

 

(4) 모듈

- 모듈을 사용해 코드를 여러 개 파일로 분할해서 작성 가능. 변수, 함수, 클래스등에 export 키워드를 사용해 모듈로 만들면 다른 파일에서도 사용할 수 있다. 모듈을 가져올 때는 import 키워드 사용

 

(5) 생성기

- 타입크스립트는 물론이고 파이썬 PHP같은 프로그래밍 언어는 yield 라는 키워드를 제공,yield문은 반복자를 의미하는 반복기를생성할 때 사용

- yield문을 사용해 반복기를 만들어 내는 반복기 제공자를 생성기라고부름

- function 키워드에 (*)를결합해 function* yield 키워드를 이용해 만들며, 타입스크립트에서 yield는 반드시 function*으로 만들어진 함수 내부에서만 사용 가능

 

(6) Promise async/await구문

- ES5로는 비동기 콜백 함수를 구현하는 것이 복잡하고 번거로움

 

- Promise는 웹 브라우저와Node.js에서 모두 제공하는 기본 타입으로 비동기 콜백 함수를 상대적으로 쉽게 구현할 목적으로 만들어짐

 

- ESNext C# 4.5 버전의async/await 구문을 빌려서 여러 개의 Promise 호출을결합한 복잡한 형태의 코드를 간결하게 구현시킴.

 

2) 타입스크립트 고유의 문법

(1) 타입 주석과 타입 추론

- 콜론(:)과 타입 이름을두고 타입 주석(Type annotation)이라고 하지만 2행처럼타입스크립트는 타입 부분 생략이 가능하며, 대입 연산자(=)의오른쪽 값을 분석해 왼쪽 변수 타입을 결정하는데 이를 타입 추론(Type inference)라고 함. 타입 추론 덕분에 자바스크립트 환경인 .js .ts로만 바꾸면 타입스크립트 환경에서 바로 동작함

Ex) let n: number = 1

let m = 2

 

(2) 인터페이스

 

(3) 튜플

- 파이썬과 같은 몇몇 프로그래밍 언어에는 튜플이라는 타입이 있으며, 물리적으로는 배열과 같지만, 배열에 저장되는 아이템의 데이터타입이모두 같으면 배열, 다르면 튜플이다.

 

(4) 제네릭 타입

- 제네릭 타입은 다양한 타입을 한꺼번에 취급할 수 있게 해주는 역할.

 

(5) 대수 타입

- ADT, 추상 데이터타입(abstract data type)을 의미하기도 하지만, 대수타입이라는 의미로도 사용됨.

- 대수 타입이란, 다른자료형의 값을 가지는 자료형을 의미

- 대수 타입은 크게 합집합(unionor sum type)과 교집합(intersection or product type) 두가지가 있으며, 합집합은 ‘|’ 기호를, 교집합은 ‘&’ 기호를 사용해 여러 타입을 결합해서 만들수 있음.

 

1-3) 타입 스크립트 개발 환경 만들기

(1) scoop 프로그램 설치

 





 

Scoop install aria2

Scoop install git

 

(2) 비주얼 스튜디오 코드 설치

- Scoop bucket add extras

- Scoop install vscode

- Add Visual Studio Code as a context menuoption by running: “C:\Scoop\apps\vscode\current\vscode-install-context.reg”

 

(3) 노드제이에스 설치

- scoop install nodejs-lts

- node -v (노드제이에스 버전 확인)

 

(4) 타입스크립트 컴파일러 설치

- npm I -g typescript

- tsc -v (타입스크립트 컴파일러 버전 확인)

 

(5) touch 프로그램 설치 파일 생성시 지정 이름의 파일이 이미 있으면 무시하고, 없으면 해당 이름으로 파일을 만들어줌

- scoop install touch

 

(6) ts-node 설치(tsc는타입스크립트 코드를 ES5 형식 자바스크립트 코드로 변환만 할 뿐 실행하지는 않으므로, 실행까지 동시에 하기 위해서 ts-node 사용)

- npm I -g ts-node

  Comments,     Trackbacks