코딩 기록

TypeScript 강좌 16. 복합형 객체, JSON, MAP 사용 방법


객체

TypeScript 객체는 JavaScript의 핵심 데이터입니다만, 클래스 등을 정의하지 않고 편하게 한 데이터만 처리할 때 사용합니다. 배열 요소에 액세스하는 방법은 인덱스(숫자)지만, 오브젝트는 문자열입니다. 키, 이름이 변수 등에서 사용할 수 있는 문자만으로 구성되었다면, 이름(문자열)을 그대로 쓸 수 있습니다. 하지만, 공백이나 마이너스 등을 포함하는 경우엔 큰따옴표나 작은따옴표로 묶어야 합니다. 또한, 키 이름에 변수를 쓴다면 [ ]로 묶습니다.


const key = 'favorite drink';

const smallAnimal = {
  name: "작은동물",
  favorite: "작은옷",
  'home town': "관악구 경찰서 있는 곳",
  [key]: "스트링 제로"
};

// 참조는 '.'+이름, 또는 [이름]
console.log(smallAnimal.name); // 작은동물
console.log(smallAnimal[key]); // 스트롱 제로

JSON (JavaScript Object Notation)

JSON이란 데이터 교환 포맷으로, 즉 문자열입니다. 일반 텍스트이며, 쓰기 쉽고 읽기 쉬운(XML과 SOAP에 비해) 면도 있고, JavaScript에서 네이티브로 취급하기 때문에 API 통신에서 사용되는 데이터 포맷으론 최고입니다.


타입스크립트에서 JSON을 파싱하면 객체와 배열로 이뤄진 계층 구조(데이터)가 완성됩니다.


JSON 오브젝트
// 첫 번째 인수에 객체나 배열, 문자열을 넣음
// 2번째 인수는 데이터 변환을 원할 때 변환 함수
// (로그 출력 시 비밀번호를 마스킹하고 싶다 등)
// 3번째는 배열과 객체로 쓸 때 쓰기 폭
// 생략 가능. 개행 없이 1줄로 출력됨
const json = JSON.stringfy(smallAnimal, null, 2);

// 아래는 복제되므로 원래의 smallAnimal과 다름
const smallAnimal2 = JSON.parse(json);


JSON은 JavaScript / TypeScript의 객체 정의보다 규칙이 엄격합니다.


예를 들어, 키는 반드시 큰따옴표로 감싸야 하고, 배열이나 객체 끝에 불필요한 쉼표가 있으면 오류입니다. 이 경우 JSON.parse()에서 SyntaxError 예외가 발생하죠. 특히 JSON이 편리하다고 마스터 데이터로 사용하여 非프로그래머와 주고받을 때 자주 발생합니다. 그리고 JSON 응답(Response 리스폰스)을 기다리는 웹 서비스에서 서버 측 오류가 발생하여 Forbidden 문자열이 돌아온 경우(403 오류 시 body 바디)에도 발생합니다.


JSON 파싱 오류
SyntaxError: Unexpected token n in JSON at position 1



객체에서 데이터 추출

객체도 배열처럼 나눠서 할당, 대입, 추출할 수 있습니다. 또한, 요소가 없을 때 기본값을 설정하거나 지정된 요소 이외의 객체를 빼낼 수 있습니다. 참고로 타입스크립트에선 한꺼번에 꺼내면 변수 이름은 반드시 개체의 키 이름이 됩니다. 함수의 반환 값과 아래의 Promise에서는 이 기법 덕분에 부담 없이 여러 정보를 한꺼번에 반환할 수 있습니다.


// 오브젝트 요소 추출
const smallAnimal = {
  name: "이순신",
  favorite: "거북선"
};

// 예전 : 하나씩 꺼내기
var name = smallAnimal.name;
var favorite = smallAnimal.favorite;
// 예전 : 존재하지 않으면 기본값 설정
var age = smallAnimal.age ? smallAnimal.age : 3;

// 지금 : 한꺼번에 꺼냄. 기본값도 설정 가능
const {name, favorite, age=3} = smallAnimal;
// 지금 : name 이외의 요소 꺼내기
const {name, ...other} = smallAnimal;


객체 요소 가공

JavaScript에서는 객체가 리터럴에서 작성할 수 있는 데이터 구조라 사용이 편리합니다. TypeScript에선 개체의 가공(복사와 합치기)도 배열과 마찬가지로 스프레드 구문으로 쉽게 처리할 수 있습니다.


const smallAnimal = {
  name: "고양이"
};

const attributes = {
  job: "소설가",
  nearStation: "강남역"
}

// 오브젝트 복사
var copy = {};
for (var key1 in smallAnimal) {
   if (smallAnimal.hasOwnProperty(key1)) {
      copy[key1] = smallAnimal[key1];
   }
}

// 예전 : Object.assign()을 사용하여 복사
const copy = Object.assign({}, smallAnimal);

// 지금 : 스프레드 구문으로 복사
const copy = {...smallAnimal};

// 오브젝트 합치기 (merge)
var merged = {};
for (var key1 in smallAnimal) {
   if (smallAnimal.hasOwnProperty(key1)) {
      merged[key1] = smallAnimal[key1];
   }
}
for (var key2 in attributes) {
   if (attributes.hasOwnProperty(key2)) {
      merged[key2] = attributes[key2];
   }
}

// 예전 : Object.assign()을 사용하여 오브젝트 합침
const merged = Object.assign({}, smallAnimal, attributes);

// 지금 : 스프레드 구문으로 합침
const merged = {...smallAnimal, ...attributes};

딕셔너리 용도로는 객체가 아니라 Map 사용

ES2015에선 단순한 배열 이외에 Map/Set이 추가됐습니다(TypeScript 적용). 배열과 같은 iterable이므로 루프를 돌릴 수 있습니다. 다른 언어처럼 리터럴로 쉽게 초기화할 수 없는 것은 단점이지만, 키와 값을 쉽게 꺼내 루프를 돌릴 수 있습니다. 타입스크립트에선 key 값만으로 for (const key of map.keys()) 루프, value 값만으로 for (const value of map.values()) 루프()도 사용할 수 있습니다.


// 예전 : 오브젝트를 map 대신 사용
var map = {
  "고돌발": "고당전쟁 영웅",
  "연남생": "고당전쟁 배신자"
};

for (var key in map) {
    if (map.hasOwnProperty(key)) {
        console.log(key + " : " + map[key]);
    }
}

// 요즘 : map 이용
// '<key, value>' 형태로 명시적인 형 지정
// 'set()'시에 틀린 데이터 들어가면 체크 가능
// 루프 등으로 값을 꺼내도 형태가 유지됨
const map = new Map<string, string>([
  ["고돌발", "고당전쟁 영웅"],
  ["연남생", "고당전쟁 배신자"]
]);

for (const [key, value] of map) {
    console.log(`${key} : ${value}`);
}


추가

Map, Set은 ES2015 이후에 도입된 클래스입니다. 타입스크립트에서도 사용할 수 있습니다.


TypeScript와 오브젝트

객체는 프로토타입이 지향하는 JavaScript의 유연성을 떠받치는 중요한 요소입니다. 한편, TypeScript는 가급적 정적 형식을 취하므로, 컴파일 시에 다양한 검사가 실시되어 오류를 찾을 수 있습니다. 개체 유형의 정의는 다음 장에서 소개합니다.


형식 정의를 하면 속성 이름의 철자나 다른 형태(자료형)를 넣는 일이 줄어 듭니다. 오류 검사 코드를 구현하는 번거로움도 줄어듭니다.



미완성 타입스크립트 강좌입니다 ...


댓글(0)