Original 변경 사항을 Fork 리파지토리에 반영하기
Fork 리파지토리의 변경은 pull request를 통해 Original에 반영할 수 있지만, 역으로 Original에서 변경된 사항을 내 Fork 리파지토리에 반영해야 할 필요가 있는 경우도 있을 것이다.
Fork 리파지토리 입장에서 바라본 Original 리파지토리는 upstream이라고 부르는데, 로컬에서 자신의 원격을 origin으로 인식하듯, Original 참조시에는 upstream을 사용하면 된다. upstream을 인식할 수 있도록 다음과 같이 등록하자. (Original의 GitHub URL 주소를 등록)
$ git remote ## remote로 등록되어 있는 저장소 주소를 보여줌
origin
$ git remote add upstream "https://github.com/engineering-skcc/engineering-skcc.github.io"
$ git remote
origin
upstream
...
$ git pull upstream master ## Original remote의 변경사항을 내 로컬로 반영
이렇게 하면 된다.
구조 분해 할당
export function InputContainer(props: InputProps) {
const { inputValue, inputChange } = props;
// ...
기업협업에서 많이 썼던 코드이다. 여기서 멘붕이었다.
하지만 공부하고 보니, 어려운 내용은 아니었다! 이걸 왜 이제 알았을까 하는 창피한 마음 뿐이었다.
이걸 또 정리해보겠다. 출처는 아래 참고
https://javascript.info/destructuring-assignment
const a = {a: 1, b: 2, c: 3}
// 같은말
const {b} = a ;
const b= a.b ;
Javascript 에서 가장 많이 사용되는 두 가지 데이터 구조는 Object, Array 이다.
- Object 를 사용하면 키별로 데이터 항목을 저장하는 단일 엔터티를 만들 수 있다.
- Array 를 사용하면 데이터 항목을 정렬된 목록으로 수집할 수 있다.
배열 분해
다음은 배열이 변수로 분해되는 방법의 예이다.
let arr = ["John", "Smith"]
let [firstName, surname] = arr;
alert(firstName); // John
alert(surname); // Smith
split 또는 다른 배열 반환 방법으로 활용할 수도 있다.
참고로 split 의 반환값은 주어진 문자열을 seperator 마다 끊은 부분 문자열을 담은 Array 이다.
let [firstName, surname] = "John Smith".split(' ');
alert(firstName); // John
alert(surname); // Smith
항목을 변수에 복사해서 "구조화 해제" 하기 때문에 "구조화 해제 할당"이라고 한다.
그래서 원배열 자체는 수정되지 않는다.
배열의 원하지 않는 요소는 추가 쉼표를 통해 버릴 수도 있다.
let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
alert( title ); // Consul
위의 코드에서 배열의 두 번째 요소는 건너뛰고 세 번째 요소는 할당되며 title의 뒤 나머지 배열 항목도 건너뛴다.
(변수가 없기 때문에).
사실, 우리는 배열뿐만 아니라 모든 이터러블(이터러블이 뭔지는 아래에 다시 언급)과 함께 사용할 수 있다.
let [a, b, c] = "abc"; // ["a", "b", "c"]
let [one, two, three] = new Set([1, 2, 3]);
여기서는 string 과 set 의 예제이다.
이렇게 왼쪽에 있는 항목에 할당할 수도 있다.
let user = {};
[user.name, user.surname] = "John Smith".split(' ');
console.log(user)
// { name: 'John', surname: 'Smith' }
entries()
let user = {
name: "John",
age: 30
};
// loop over keys-and-values
for (let [key, value] of Object.entries(user)) {
alert(`${key}:${value}`); // name:John, then age:30
}
" Object.entries()는 object에 직접있는 enumerable 속성 [key, value] 쌍에 해당하는 배열을 반환한다. 속성의 순서는 개체의 속성 값을 수동으로 반복하여 주어진 순서와 동일하다. "
위와 유사 코드
let user = new Map();
user.set("name", "John");
user.set("age", "30");
// Map iterates as [key, value] pairs, very convenient for destructuring
for (let [key, value] of user) {
alert(`${key}:${value}`); // name:John, then age:30
}
일반적으로 배열이 왼쪽 목록보다 길면 "추가" 항목이 생략된다.
let [name1, name2] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
alert(name1); // Julius
alert(name2); // Caesar
다음에 나오는 모든 것을 수집하려면 점 세 개를 사용하여 "나머지"를 가져오는 매개변수를 하나 더 추가할 수 있다 "..."
let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
// rest is array of items, starting from the 3rd one
alert(rest[0]); // Consul
alert(rest[1]); // of the Roman Republic
alert(rest.length); // 2
rest 의 값은 나머지 배열 요소이다!
let [name1, name2, ...titles] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
// now titles = ["Consul", "of the Roman Republic"]
배열이 왼쪽 목록보다 짧으면 오류가 발생하지 않는다. 없는 값은 정의되지 않은 것으로 간주된다.
let [firstName, surname] = [];
alert(firstName); // undefined
alert(surname); // undefined
객체 분해
Destructing 할당은 객체에서도 작동된다.
기본 구문은 다음과 같다.
let {var1, var2} = {var1: ..., var2: ...}
여기서 변수로 분할하려는 기존 개체가 오른쪽에 있어야 한다.
예를 들어
let options = {
title: "Menu",
width: 100,
height: 200
};
let {title, width, height} = options;
alert(title); // Menu
alert(width); // 100
alert(height); // 200
let {height, width, title} = { title: "Menu", height: 200, width: 100 }
참고로 순서는 중요하지 않다.
let options = {
title: "Menu",
width: 100,
height: 200
};
// { sourceProperty: targetVariable }
let {width: w, height: h, title} = options;
// width -> w
// height -> h
// title -> title
alert(title); // Menu
alert(w); // 100
alert(h); // 200
위의 코드에서 콜론은 "무엇: 어디로 가는가" 를 나타낸다.
위의 예에서 width 속성은 w 속성으로 이동하고 height 속성은 h 속성으로 이동한다.
아래와 같이 콜론이 누락되어도 된다.
let options = {
title: "Menu"
};
let {width = 100, height = 200, title} = options;
alert(title); // Menu
alert(width); // 100
alert(height); // 200
let options = {
title: "Menu"
};
let {width: w = 100, height: h = 200, title} = options;
alert(title); // Menu
alert(w); // 100
alert(h); // 200
속성이 많은 복잡한 객체가 있는 경우 필요한 것만 추출할 수 있다.
let options = {
title: "Menu",
width: 100,
height: 200
};
// only extract title as a variable
let { title } = options;
alert(title); // Menu
나머지 패턴 "..."
객체에 변수가 있는 것보다 더 많은 속성이 있으면 어떻게 될까? 일부를 가져온 다음 "나머지"를 어딘가에 할당할 수 있을까?
배열과 마찬가지로 나머지 패턴을 사용할 수 있다.
let options = {
title: "Menu",
height: 200,
width: 100
};
// title = property named title
// rest = object with the rest of properties
let {title, ...rest} = options;
// now title="Menu", rest={height: 200, width: 100}
alert(rest.height); // 200
alert(rest.width); // 100
만약 위 예제에서 title 대신 height 였다면 rest 에는 그 나머지가 저장될 것이다.
중첩된 구조 분해
개체 또는 배열에 다른 중첩 개체 및 배열이 포함되어 있으면 더 복잡한 왼쪽 패턴을 사용하여 더 깊은 부분을 추출할 수 있다.
let options = {
size: {
width: 100,
height: 200
},
items: ["Cake", "Donut"],
extra: true
};
// destructuring assignment split in multiple lines for clarity
let {
size: { // put size here
width,
height
},
items: [item1, item2], // assign items here
title = "Menu" // not present in the object (default value is used)
} = options;
alert(title); // Menu
alert(width); // 100
alert(height); // 200
alert(item1); // Cake
alert(item2); // Donut
size 나 item 은 꺼낼 수 없다.
(size is undefined 오류가 뜬다)
스마트 기능 매개변수
함수에 많은 매개변수가 있는 경우가 있으며 대부분은 선택사항이다.
사용자 인터페이스의 경우 특히 그렇다.
메뉴를 생성하는 함수가 있다고 가정하자.
이 함수는 너비, 높이, 제목, 항목 목록 등이 있을 수 있다.
// we pass object to function
let options = {
title: "My menu",
items: ["Item1", "Item2"]
};
// ...and it immediately expands it to variables
function showMenu({title = "Untitled", width = 200, height = 100, items = []}) {
// title, items – taken from options,
// width, height – defaults used
alert( `${title} ${width} ${height}` ); // My Menu 200 100
alert( items ); // Item1, Item2
}
showMenu(options);
매개변수를 객체로 전달할 수 있고, 함수는 이를 즉시 변수로 구조화한다.
중첩된 객체와 콜론 매핑을 사용하여 더 복잡한 구조 분해를 사용할 수도 있다.
let options = {
title: "My menu",
items: ["Item1", "Item2"]
};
function showMenu({
title = "Untitled",
width: w = 100, // width goes to w
height: h = 200, // height goes to h
items: [item1, item2] // items first element goes to item1, second to item2
}) {
alert( `${title} ${w} ${h}` ); // My Menu 100 200
alert( item1 ); // Item1
alert( item2 ); // Item2
}
showMenu(options);
요약
구조 분해 할당을 사용하면 객체 또는 배열을 많은 변수에 즉시 매핑 할 수 있다.
let {prop : varnamr = default, ...rest} = object
이는 속성 prop 이 변수 varname 에 들어가야 하고, 그러한 속성이 없으면 default 값을 사용해야 함을 의미한다.
매핑 되지 않은 개체 속성은 rest 객체에 들어간다.
배열도 마찬가지이다.
let [item1 = default, item2, ...rest] = array
rest 에는 나머지 배열을 만든다.
점검
let user = {
name: "John",
years: 30
};
구조화 할당을 작성해라
1. name 속성을 name 변수에 넣는다.
2. years 속성을 age 변수에 넣는다.
3. isAdmin 속성을 age 변수에 추가한다. (해당 속성이 없으면 false)
정답
let user = {
name: "John",
years: 30
};
let {name, years: age, isAdmin = false} = user;
alert( name ); // John
alert( age ); // 30
alert( isAdmin ); // false
다음과 같은 salaries 객체가 있다.
let salaries = {
"John": 100,
"Pete": 300,
"Mary": 250
};
topSalary(salaries) 로 가장 많이 받는 사람의 이름을 반환하는 함수를 만들어라
단, salaries 가 비어있으면 null 을 반환해야 한다.
최고 급여를 받는 사람이 여러 명인 경우 그 중 한명을 반환한다.
Object.entries 를 사용해서 구조를 해제해라.
function topSalary(salaries) {
let maxSalary = 0;
let maxName = null;
for(const [name, salary] of Object.entries(salaries)) {
if (maxSalary < salary) {
maxSalary = salary;
maxName = name;
}
}
return maxName;
}
Iterable
반복 가능한 객체(iterable object)는 for...of 구문과 함께 ES2015에서 도입되었다. 반복 가능한 객체를 다른 객체와 구분짓는 특징은, 객체의 Symbol.iterator 속성에 특별한 형태의 함수가 들어있다는 것이다.
객체의 Symbol.iterator 속성에 특정 형태의 함수가 들어있다면, 이를 반복 가능한 객체(iterable object) 혹은 줄여서 iterable이라 부르고, 해당 객체는 iterable protocol을 만족한다고 말합니다. 이런 객체들에 대해서는 ES2015에서 추가된 다양한 기능들을 사용할 수 있습니다.
내장된 생성자 중 iterable 객체를 만들어내는 생성자에는 아래와 같은 것들이 있습니다.
- String
- Array
- TypedArray
- Map
- Set
어떤 객체가 Iterable이라면, 그 객체에 대해서 아래의 기능들을 사용할 수 있다.
- for...of 루프
- spread 연산자 (...)
- 분해대입(destructuring assignment)
- 기타 iterable을 인수로 받는 함수
// `for...of`
for (let c of 'hello') {
console.log(c);
}
// -> 'h' 'e' 'l' 'l' 'o'
// spread 연산자
const characters = [...'hello'];
// -> [ 'h', 'e', 'l', 'l', 'o' ]
// 분해대입
const [c1, c2] = 'hello';
// `Array.from`은 iterable 혹은 array-like 객체를 인수로 받습니다.
Array.from('hello');
// -> [ 'h', 'e', 'l', 'l', 'o' ]
let range = {
from: 1,
to: 5
};
// 아래와 같이 for..of가 동작할 수 있도록 하는 게 목표입니다.
// for(let num of range) ... num=1,2,3,4,5
let [a, b, c] = "abc"; // ["a", "b", "c"]
let [one, two, three] = new Set([1, 2, 3]);
export default 와 export 의 차이가 뭘까?
기업협업하는 도중 대체 이 둘의 차이는 뭘까 생각하면서도 굳이 찾아보지 않았는데 팀장님이 알려주셨다.
다시 구글링을 바탕으로 이 둘의 차이점을 정리해보겠다.
일단 모듈부터 알아보자.
모듈 소개
개발하는 애플리케이션의 크기가 커지면 언젠간 파일을 여러 개로 분리해야 하는 시점이 옵니다. 이때 분리된 파일 각각을 '모듈(module)'이라고 부르는데, 모듈은 대개 클래스 하나 혹은 특정한 목적을 가진 복수의 함수로 구성된 라이브러리 하나로 구성됩니다.
선언부 앞에 export 붙이기
변수나 함수, 클래스를 선언할 때 맨 앞에 export 를 붙이면 내보내기 가능하다.
// 배열 내보내기
export let months = ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
// 상수 내보내기
export const MODULES_BECAME_STANDARD_YEAR = 2015;
// 클래스 내보내기
export class User {
constructor(name) {
this.name = name;
}
}
>> 클래스나 함수를 내보낼 땐 세미콜론을 붙이지 말기
export function sayHi(user) {
alert(`Hello, ${user}!`);
} // 끝에 ;(세미콜론)을 붙이지 않습니다.
선언부와 떨어진 곳에 export 붙이기
선언부와 export 가 떨어져 있어도 내보내기 가능하다.
아래 예시에선 함수를 먼저 선언한 후, 마지막 줄에서 내보낸다.
// 📁 say.js
function sayHi(user) {
alert(`Hello, ${user}!`);
}
function sayBye(user) {
alert(`Bye, ${user}!`);
}
export {sayHi, sayBye}; // 두 함수를 내보냄
참고로 export 문을 함수 선언부 위에 적어주는 것도 동일하게 동작된다.
import *
무언갈 가져오고 싶다면 아래와 같이 이에 대한 목록을 만들어 import {...} 안에 적어주면 된다.
// 📁 main.js
import {sayHi, sayBye} from './say.js';
sayHi('John'); // Hello, John!
sayBye('John'); // Bye, John!
가져올 것이 많으면 import * as <obj> 처럼 객체 형태로 원하는 것들을 가지고 올 수 있다.
예시를 살펴보자.
// 📁 main.js
import * as say from './say.js';
say.sayHi('John');
say.sayBye('John');
이렇게 '한꺼번에 모든 걸 가져오는 방식'을 사용하면 코드가 짧아진다.
그런데도 어떤 걸 가져올 땐 그 대상을 구체적으로 명시하는게 좋다.
이렇게 하는데 이유는 .....
1. 웹팩(webpack) 과 같은 모던 빌드 툴은 로딩 속도를 높이기 위해 모듈들을 한데 모으는 번들링과 최적화를 수행한다.
이 과정에서 사용하지 않는 리소스가 삭제되기도 한다.
아래와 같이 프로젝트에 서드파티 라이브러리인 say.js 를 도입하였다 가정하자. 이 라이브러리엔 수 많은 함수가 있다.
// 📁 say.js
export function sayHi() { ... }
export function sayBye() { ... }
export function becomeSilent() { ... }
현재로선 say.js 의 수 많은 함수 중 단 하나만 필요하기 때문에, 이 함수만 가져와 보겠다.
// 📁 main.js
import {sayHi} from './say.js';
빌드 툴은 실제 사용되는 함수가 무엇인지 파악해, 그렇지 않은 함수는 최종 번들링 결과물에 포함하지 않는다.
이 과정에서 불필요한 코드가 제거되기 때문에 빌드 결과물의 크기가 작아진다.
이런 최적화 과정은 '가지치기'라고 불린다.
2. 어떤 걸 가지고 올지 명시하면 이름을 간결하게 써줄 수 있다.
say.sayHi( ) 보다 sayHi( ) 가 더 간결하다.
3. 어디서 어떤게 쓰이는지 명확하기 때문에 코드 구조를 파악하기가 쉬워 리팩토링이나 유지보수에 도움이 된다.
import 'as'
as 를 사용하면 이름을 바꿔서 모듈을 가져올 수 있다.
sayHi 를 hi 로, sayBye 를 bye 로 이름을 버꿔서 가져와 보자.
// 📁 main.js
import {sayHi as hi, sayBye as bye} from './say.js';
hi('John'); // Hello, John!
bye('John'); // Bye, John!
Export 'as'
export 에도 as 를 사용할 수 있다.
sayHi 와 sayBye 를 각각 hi, bye 로 이름을 바꿔 내보내보자.
// 📁 say.js
...
export {sayHi as hi, sayBye as bye};
이제 다른 모듈에서 이 함수들을 가져올 때 이름은 hi 와 bye 가 된다.
// 📁 main.js
import * as say from './say.js';
say.hi('John'); // Hello, John!
say.bye('John'); // Bye, John!
export default
모듈은 크게 두 종류로 나뉜다.
1. 복수의 함수가 있는 라이브러리 형태의 모듈(위 예시의 say.js)
2. 개체 하나만 선언되어 있는 모듈(아래의 user.js. class User 하나만 내보내기 함)
대개는 두 번째 방식으로 모듈을 만드는 걸 선호하기 때문에 함수, 클래스, 변수 등의 개체는 전용 모듈 안에 구현된다.
그런데 이렇게 모듈을 만들다보면 자연스레 파일 개수가 많아질 수 밖에 없다. 그렇더라도 모듈 이름을 잘 지어주고, 폴더에 파일을 잘 나눠 프로젝트를 구성하면 코드 탐색이 어렵지 않으므로 이는 전혀 문제가 되지 않는다.
모듈은 export default 라는 특별한 문법을 지원한다.
export default 를 사용하면 '해당 모듈엔 개체가 하나만 있다'는 사실을 명확히 나타낼 수 있다.
내보내고자 하는 개체 앞에 export default 를 붙여보자.
// 📁 user.js
export default class User { // export 옆에 'default'를 추가해보았습니다.
constructor(name) {
this.name = name;
}
}
파일 하나엔 대개 export default 가 하나만 있다.
이렇게 default 를 붙여서 모듈을 내보내면 중괄호(Curly Brackets) 없이 모듈을 가져올 수 있다.
// 📁 main.js
import User from './user.js'; // {User}가 아닌 User로 클래스를 가져왔습니다.
new User('John');
중괄호 없이 클래스를 가져오니 더 깔끔해 보인다.
모듈을 막 배우기 시작한 사람은 중괄호를 빼먹는 실수를 자주 한다.
named export 한 모듈을 가져오려면 중괄호가 필요하고, default export 한 모듈을 가져오려면 중괄호가 필요하지 않다는 걸 기억해 실수를 방지한다.
사실 named export 와 default export 를 같은 모듈에서 동시에 사용해도 문재는 없다.
그런데 실무에선 이렇게 섞어 쓰는 사례가 흔치 않다.
한 파일엔 named export 나 default export 둘 중 하나만 사용한다.
파일당 최대 하나의 default export 가 있을 수 있으므로 내보낼 개체엔 이름이 없어도 괜찮다.
아래 예시의 개체엔 이름이 없지만 모두 에러 없이 잘 동작한다.
export default class { // 클래스 이름이 없음
constructor() { ... }
}
export default function(user) { // 함수 이름이 없음
alert(`Hello, ${user}!`);
}
// 이름 없이 배열 형태의 값을 내보냄
export default ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
export default 는 파일당 하나만 있으므로 이 개체를 가져오기 하려는 모듈에선 중괄호 없이도 어떤 개체를 가지고 올지 정확히 알 수 있으므로 이름이 없어도 괜찮다.
default 를 붙이지 않았다면 개체에 이름이 없는 경우 에러가 발생한다.
export class { // 에러! (default export가 아닌 경우엔 이름이 꼭 필요합니다.)
constructor() {}
}
'default' name
default 키워드는 기본 내보내기를 참조하는 용도로 종종 사용된다.
함수를 내보낼 때 아래와 같이 함수 선언부와 떨어진 곳에서 default 키워드를 사용하면, 해당 함수를 기본 내보내기 할 수 있다.
function sayHi(user) {
alert(`Hello, ${user}!`);
}
// 함수 선언부 앞에 'export default'를 붙여준 것과 동일합니다.
export {sayHi as default};
흔치 않지만 user.js 라는 모듈에 'default' export 하나와 다수의 named export 가 있다고 해보자.
// 📁 user.js
export default class User {
constructor(name) {
this.name = name;
}
}
export function sayHi(user) {
alert(`Hello, ${user}!`);
}
아래와 같은 방식을 사용하면 default export 와 named export 를 동시에 가져올 수 있다.
// 📁 main.js
import {default as User, sayHi} from './user.js';
new User('John');
default export 의 이름에 관한 규칙
named export 는 내보냈을 때 사용한 이름 그대로 가져오므로 관련 정보를 파악하기가 쉽다.
그런데 아래와 같이 내보내기 할 때 쓴 이름과 가져오기 할 때 쓸 이름이 동일해야 한다는 제약이 있다.
named export 와는 다르게 default export 는 가져오기 할 때 개발자가 원하는 대로
이름을 지정해 줄 수 있다.
import User from './user.js'; // 동작
import MyUser from './user.js'; // 동작
// 어떤 이름이든 에러 없이 동작합니다.
그런데 이렇게 자유롭게 이름을 짓다 보면 같은 걸 가져오는데도 이름이 달라 혼란의 여지가 생길 수 있따.
이런 문제를 예방하고 코드의 일관성을 유지하기 위해 default export 한 것을 가져올 땐 아래와
같이 파일 이름과 동일한 이름을 사용하도록 팀원끼리 내부 규칙을 정할 수 있다.
import User from './user.js';
import LoginForm from './loginForm.js';
import func from '/path/to/func.js';
...
그런데 규칙이 있어도 이를 지키지 않는 사람이 있을 수 있기 때문에 어떤 팀은 named export 만 사용할 것을 강제하는 경우도 있다. 모듈 하나에서 단 하나의 개체만 내보내는 경우에도 default 없이 이름을 붙여
내보내면 혼란을 방지할 수 있다.
이런 규칙은 아래에서 배울 모듈 다시 내보내기를 쉽게 해준다는 장점도 있다.
모듈 다시 내보내기
export ... from ... 문법을 사용하면 가져온 개체를 즉시 '다시 내보내기(re-export)' 할 수 있다.
이름을 바꿔서 다시 내보낼 수 있는 것이다.
인터페이스 읽기 전용 속성
interface Notebook {
readonly CPU: string;
readonly RAM: string;
};
인터페이스 이행이 지정된 객체의 readonly로 지정된 속성을 할당 이후, 임의로 변경 시도하면 오류가 발생합니다.
let mackbook:Notebook = {
CPU: '2.9GHz 코어 i9',
RAM: '32GB'
};
// [오류]
// 'RAM'은 읽기 전용 속성 또는 상수로 변경할 수 없습니다.
// (property) Notebook["RAM"]: string
macbook.RAM = '128GB';
interface ButtonInterface {
readonly _type:string;
width?:number;
height?:number;
onInit?():void;
onClick():void;
}
클래스를 상속하는 클래스가 있듯이, 인터페이스 또한 extends 키워드를 사용해 인터페이스를 확장 할 수 있습니다.
// ButtonInterface를 확장하는 ToggleButtonInterface
interface ToggleButtonInterface extends ButtonInterface {
toggle():void;
onToggled?():void;
}
인터페이스 확장
클래스와 마찬가지로 인터페이스는 서로를 확장할 수 있습니다. 이렇게 하면 한 인터페이스의 구성원을 다른 인터페이스로 복사할 수 있으므로 인터페이스를 재사용 가능한 구성 요소로 분리하는 방법을 보다 유연하게 사용할 수 있습니다.
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
Container + presenter 패턴
container + presenter 패턴은
데이터처리와 데이터출력을 분리하는 것이다
즉,
Container에서는 API Request, Exception Error, state변경, redux, dispatch...
Presenter에서는 props, UI... 를 관리하는 것이다
Container에서 처리하거나 받아온 데이터들을 Presenter 컴포넌트에 props로 넘긴다
Container Presenter 방식의 장점?
데이터 처리부분과 보여지는 부분이 나뉘어 있다는 것!
데이터를 보여주는 부분을 수정하고 싶으면 Presenter파일로 가면 되고, 데이터 요청 및 처리에 관련된 코드를 구현하고 싶다면 Container파일로 가서 코드를 작성하면 된다
https://velog.io/@dolarge/React-Container-Presenter-%ED%8C%A8%ED%84%B4
[Typescript] 배열 안 타입을 정의하는 방법
타입스크립트를 사용하면서 항상 빼놓을 수 없는 순간은 '타입 정의(Type Definition)'다.
보통 Interface나 Type Alias를 사용하면서 타입 정의를 하지만 배열 안 Type을 정의 할 때 어떻게 해야하는지 궁금해서 찾아봤다.
예를 들어, 이러한 코드가 있다고 가정해보자.
const arr: Array<object> = [{
name : 'test',
age : 12,
isShowing: true
}]
선언된 매개변수를 그대로 사용할 시 아래와 같은 오류를 마주할 수 있다.
말 그대로 arr에 매개변수 안에 isShowing이라는 프로퍼티가 object 안에 없다는 얘기다.
이럴 때는 Custom하게 Interface를 사용하여 직접 object 안의 isShowing 대한 Type을 선언해 줘야한다.
먼저 인터페이스의 대한 이름을 TestInterface로 지정해주고 export하여 내보낼 interface의 대한 정의를 하고 그 뒤
extends를 추가하여 Array에 TestInterface를 넣어 Array안 object 안의 프로퍼티에 대한 Type을 선언 할 수 있다.
출처: https://soft91.tistory.com/78 [너와 나의 프로그래밍]
'👩🏻💻 TIL' 카테고리의 다른 글
프리즈마, 그래프큐엘의 yarn codegen (0) | 2022.02.21 |
---|---|
2022_02_09_TIL (0) | 2022.02.10 |
GraphQL (0) | 2022.01.04 |
쿼리 루트 타입, mutation (0) | 2022.01.01 |
ORM - prisma (0) | 2021.12.31 |