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)

Designed by JB FACTORY