[효리]공통 콜백 함수를 위한 타입 선언을 제공하는 것이 좋다? 예시가 없으니 잘 이해가 안된다.
[재희] 공통 콜백 함수? 그냥 매개변수의 타입과 리턴 타입이 공통된 콜백 함수를 얘기하는 것 같다.
[효리] 아하. 뭔가 다른 개념이 있는 줄 알았다.
13. 타입과 인터페이스의 차이점 알기
[지윤] “프로젝트 내부적으로 사용되는 타입에 선언 병합이 발생하는 것은 잘못된 설계이다.” 이 부분이 조금 헷갈린다. 인터페이스만 선언 병합이 되는 게 아니었나? 타입(타입 별칭)에서도 일어난다는 뜻인가?
[효리]타입(타입 별칭)이 아니고 타입 자체를 말하는 것 같다.
[재희] 인터페이스를 한 프로젝트 내에서 보강을 할 일이 뭐가 있을까? ES5 → ES2015 버전으로 업데이트하는 예시를 책에서 들어줬는데, 우리 같은 경우는 회사에서 기존 프로젝트의 레거시를 새 버전으로 업데이트할 때 등을 예시로 들 수 있을 것 같다. 기존 타입 선언을 보강해서 사용할 수 있을 것 같다.
😒
[동호] 레거시가 타입 별칭으로 선언되어 있으면 어떡하죠…
[재희] 그럼 뭐.. 인터페이스로 새로 작성해야죠.
[동호] 그렇습니다. [재희] 그렇습니다.
14. 타입 연산과 관련된 제너릭 사용으로 반복 줄이기
[지윤] ‘K’ 타입은 string, number, symbol 저 부분. 원래 number도 들어가나?
[재희] 그렇다. 객체의 키로 될 수 있는 것들 string, number, symbol 이 있다.
[지윤] string, symbol만 되는 줄 알았다.
16. 동적 데이터에 인덱스 시그니처 사용하기
[동호] 이 파트 좀 모르겠다. string 대신 number를 key 타입으로 사용할 일이… 있나? 싶다.
[재희] 배열 메서드에서 쓰이는 인덱싱을 위한 키가 number로 작용하는데, 우리가 만든 key는 string이다. 원래는 자바스크립트에서 안되는데, 타입스크립트에서는 그냥 허용해줬다. 이렇게 이해했다.
[동호] 약간 코드 돌리고 나서 ‘이거 왜 되지?’ 이런 질문의 답이 되는 부분일까?
[재희] 그런 것 같다. 이런 코드 스타일이 자주 쓰이니까 허용하지 않았을까?
[지윤]const xs가 배열로 되어 있는데, 배열이나 튜플일 때만 되는건가? lib.es5.d.ts에 선언된 Array 인터페이스의 키 타입은 number로만 되어 있다.
[재희] 그럼 string이 들어갔을 때는 어떻게 되는거지..? 따로 엔진 처리가 되는가? string도 허용하는 명세가 있지 않을까? 한 번 알아보자.
17. 변경 관련된 오류 방지를 위해 readonly 사용하기
[효리] readonly 배열에 readonly 배열을 만들 때는 그럼 이렇게 쓰면 될까?
[재희] 그런 것 같다. 검증해보겠다. (주섬주섬 타입스크립트 플레이그라운드를 키며)
[재희] 맞다. 그렇게 작성하면 된다.
[효리] 감삼다
18. 매핑된 타입을 사용하여 값을 동기화하기
[효리] 아래 첫 번째 코드가 보수적(실패에 닫힌) 접근법이고, 아래가 실패에 열린 접근법이다. 실패에 열린 접근법은 불필요한 렌더링을 줄였다는데, 이 부분이 와닿질 않는다. 둘이 똑같지 않은가?
[동호] 나도 잘 이해 안됐다.
[재희] 책 예제가 조금 헷갈린다. 타입스크립트 내용은 아니지만, 이 ScatterProps 인터페이스에 요소가 더 추가되었을 때를 생각해보면 될 것 같다. 실패에 열린 접근법은 일일이 하나 하나 개발자가 추가해주어야 한다. 보수적 접근법의 경우에는 모든 속성의 변경 사항에 대해 모두 렌더링한다.
[동호] 아 새로 추가될 속성의 값이 변할 때 렌더링이 필요한지 아닌지 모르니까?
[재희] ㅇㅇ. 이건 뭐 접근법에 따라 다른거니까
[진욱] 이걸 보면서 실패에 닫힌, 열린 접근법인데 여기서 실패가 뭘까? 고민해봤다. 개발자가 실수로 인터페이스를 변경하면 shouldUpdate도 변경해야 하는데, 그 때 바꿔주지 않는 것을 실패라고 하는 것 같다고 생각했다. 실패에 닫혔으니 실수하더라도 렌더링을 시켜주는 것이고, 실패에 열려있으니 실수하더라도 좀 관대한것 같다. 렌더링을 안해주니.
[효리] 렌더링 안해주는게 관대한건가..?
[재희] 보수적이면 까먹었을 때 냅다 갈겨버리는데, 열려있을 때는 까먹으면 얘도 넘어가버리니까…
[효리] 헷갈리는데 새 단어를 만드는게..? 엄근법으로 만들자
[동호] 더 헷갈리는데… 이건 일단 타입스크립트 내용은 아니니까 넘어가자
추가 논의
[진욱] 어제 재희님이 슬랙에 올리셨던 내용에 관련해서 생각한 게 있다.
[진욱] 아래 코드를 보자. 이 부분을 보면서 생각한게, 타입 좁히기(narrowing) 관점에서 우리가 in 연산자를 간과한게 아닌가? 깜빡한게 아닐까? 그냥 이렇게 쓰면 되는데.
[진욱] 이거 책 125페이지에 완전 똑같은 예시가 나온다.
[재희] 타입 좁히기에 대해서도 우리가 좀 더 공부해봐야 할 것 같다.
type Pick<T, K> = { [k in K]: T[K] } // 'K' 타입은 'string | number | symbol' 타입에 할당할 수 없습니다.
// k는 T 타입과 무관하고 범위가 너무 넓다.
// K는 인덱스로써 사용이 가능한 string | number | symbol 타입이 되어야 한다.
// 실제로는 K는 T의 키의 부분 집합이 되어야 한다.
type Pick<T, K extends keyof T> = { [k in K]: T[K] }
const xs = [1, 2, 3]
const keys = Object.keys(xs) // 타입이 string[]
for (const key in keys) {
key // 타입이 string
const x = xs[key] // 타입이 number
}
// string이 number에 할당될 수 없기 때문에 이상하다.
// 배열을 순회하는 코드 스타일에 대한 실질적인 허용이라고 생각하는 것이 좋다.
// for-of 를 사용하거나, forEach를 사용하는 것이 낫다.
// 보수적 접근법(실패에 닫힌 접근법)
// 새로운 속성이 추가되면 shouldUpdate 함수는 값이 변경될 때마다 차트를 다시 그림
function shouldUpdate(oldProps: ScatterProps, newProps: ScatterProps) {
let k: keyof ScatterProps // 'xs' | 'ys' | 'xRange' | 'yRange' | 'color'
for (k in oldProps) {
if (oldProps[k] !== newProps[k]) {
if (k !== 'onClick') return true
}
}
return false
}
// 실패에 열린 접근법
// 차트의 불필요하게 그려지는 단점은 해결되지만, 누락될 수 있다.
function shouldUpdate(oldProps: ScatterProps, newProps: ScatterProps) {
return (
oldProps.xs !== newProps.xs ||
oldProps.ys !== newProps.ys ||
oldProps.xRange !== newProps.xRange ||
oldProps.yRange !== newProps.yRange ||
oldProps.color !== newProps.color
// (no check for onClick)
)
}
function gett(a: A|B) {
if('b' in a) {
console.log(a.b)
}
}