-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[TypeScript & Module Typing] 아놀드(한수빈) 미션 제출합니다. #10
[TypeScript & Module Typing] 아놀드(한수빈) 미션 제출합니다. #10
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 아놀드~ 아놀드의 코드 리뷰를 하다니 영광입니다 하하
오히려 제가 코드 리뷰하면서 많이 배웠습니다.
터놓고 프로젝트에 ValueOf 타입 분리하신것도 간결하구 좋네요!
부족한 실력으로 질문 몇개랑 리뷰 몇개 남겨보았습니다
그리구.. api 테스트는 진행안해주셔서 그런지 테스트가 안돌아가네요 ~ 허허
아무튼 고생하셨습니다 ! 역시... 짱 !
function addEvent<T extends keyof GlobalEventHandlersEventMap>( | ||
type: T, | ||
listener: (e: GlobalEventHandlersEventMap[T]) => void | ||
) { | ||
element.addEventListener(type, listener); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
와 호프 인터페이스에 대한 문서까지 찾아주시다니 너무 감사합니다!!
저는 문서보다는 코드를 믿는 편이거든요!
vscode에서 지원해주는 정의로 이동
기능을 이용해서 살펴본 결과
interface HTMLElementEventMap extends ElementEventMap, DocumentAndElementEventHandlersEventMap, GlobalEventHandlersEventMap {
}
이러한 코드를 볼 수 있었습니다.
즉, GlobalEventHandlersEventMap
가 더 좁은 타입이였던 거죠!
그렇기에 위 타입을 사용했습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그렇군요 감사합니다 !! 👍
문서보다는 직접 타입이 어떻게 정의되어 있는지를 확인하는게 좋겠군요!
type FetchBodyType = | ||
| string | ||
| URLSearchParams | ||
| FormData | ||
| Blob | ||
| ArrayBuffer | ||
| ArrayBufferView | ||
| DataView; | ||
|
||
type Url = `http${'' | 's'}://${string}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BodyType 과 Url 타입까지 꼼꼼하게 잡아주셨네요 굿👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
감사합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
호프의 질문
- Url 타입까지 잡아줘야하나? 어디까지 타입가드를 해줘야하나?
아놀드의 말씀
타입스크립트를 사용하는 이유란..?
- 자바스크립트 환경에서 런타임 에러들을 타입스크립트를 통해 컴파일단에서 잡으려고 사용한다.
- 런타임 에러는 휴먼에러까지 포함된다.
- fetch 에 url 을 string 으로 주면 abc 이런 잘못된 url 도 들어올텐데, 이게 런타임 에러를 유발할 것인데, 이걸 타입스크립트로 잡을 수 있지 않을까요 ??
👍
return new Promise((resolve, reject) => { | ||
const response: Response<Data> = { | ||
status: 200, | ||
ok: true, | ||
statusText: 'example code', | ||
json: () => { | ||
return new Promise((resolve, reject) => { | ||
resolve('아무튼 데이터임..!' as unknown as Data); | ||
}); | ||
}, | ||
}; | ||
|
||
resolve(response); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오호 👍 👍 이렇게 구현해주셨군요 대단합니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
호프의 질문: 왜 타입단언에 as unknown 을 붙여야할까요?
아놀드의 말씀
- 왜
as Data
하면 에러가 뜰까요? - 두 형식이 충분히 겹치지 않기 때문이다.
개발자 : "너 이거 타입 이렇게 달거라"
타입스크립트 : "주인님~ 아무리그래도 이건 좀 선넘지 않습니까? ㅠㅠ 니가 내 주인이라니. 삭제해주세요 차라리.."
타입스크립트: -> as unknown 으로 하면 " 아잇..난 안볼란다..ㅠ..니 멋대로해라. 모르쇠!"
type Nullable<T> = T extends null ? T : never; | ||
export function isNull<T>(value: T): value is Nullable<T> { | ||
return value === null; | ||
} | ||
|
||
type Nilable<T> = T extends null | undefined ? T : never; | ||
export function isNil<T>(value: T): value is Nilable<T> { | ||
return isNull(value) || value === undefined; | ||
} | ||
|
||
type Numberable<T> = T extends number ? T : never; | ||
export function isNumber<T>(value: T): value is Numberable<T> { | ||
return typeof value === 'number'; | ||
} | ||
|
||
type Functionable<T> = T extends Function ? T : never; | ||
export function isFunction<T>(value: T): value is Functionable<T> { | ||
return typeof value === 'function'; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value is type
으로 리턴 타입을 설정하면 잘못된 인수를 넣어도 마우스 커서를 올렸을 때 value is type
식으로만 함수의 리턴 타입을 알려줍니다.
-*able 처럼 조건부 타입을 정의하고 리턴 타입으로 사용한다면 잘못된 인수를 넣었을 때 조건에 맞게 value is type | value is never
형식으로 컴파일 단에서 true를 반환할지 false를 반환할지 알려주기 때문에 매우 편리합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아놀드의 말씀
사용자 정의 타입가드란?
- 말그대로 boolean, number 와 같은 원시타입이라던지 함수타입이라던지 언어단에서 존재하는거잖아요? value is~ 이런건 듣도보도 못한 타입이잖아요. 이런 구문을 사용자 정의 타입가드라고 합니다.
nullable 쓴 이유
- hover 했을 때 잘못된 타입일 경우 value is never 로 뜬다.
export function pick<T extends Record<string, unknown>, R extends keyof T>( | ||
obj: T, | ||
...keys: R[] | ||
): Pick<T, R> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
타입이 아주 잘 잡혀있네용 구웃 👍 👍
__tests__/type.test.ts
Outdated
|
||
expectType<{ a: 1; b: 2 }>(_.pick({ a: 1, b: 2, c: 3 }, 'a', 'b')); | ||
|
||
expectType<{ c: number }>(_.omit({ a: 1, b: 2, c: 3 }, 'a', 'b')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
왜 pick 과 달리 omit 은 반환되는 객체의 프로퍼티 타입을 리터럴로 못잡고 더 넓게 number 로 잡을까요 ??
{c: 3} 을 넣었더니 Type 'number' is not assignable to type '3'.
이라구 나오네요.
function pick<T extends Record<string, unknown>, R extends keyof T>(
obj: T,
...keys: R[]
): Pick<T, R> {
return keys.reduce((acc, key) => {
acc[key] = obj[key];
return acc;
}, {} as Pick<T, R>);
}
function omit<T extends Record<string, unknown>, R extends keyof T>(
obj: T,
...keys: R[]
): Omit<T, R> {
return keys.reduce(
(acc, key) => {
delete acc[key];
return acc;
},
{ ...obj }
);
}
제 예상에는
pick 함수에서는 위와 같이 타입 단언을 해준 빈 객체를 reduce 기본값으로 갖고
omit 함수는 기존의 Record<string, unknown>
extends 하는 obj 를 기본값으로 가져서 그런 것 같아요
그러면 omit 도 Pick 처럼 정확히 타입이 잡힌 객체를 반환하도록 동작하게 하면 어떨까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
와 시도해보고 있는데 빡세네용; 호프한테 물어보면서 해야겠어요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
너무 어려워요 ㅠㅠ 아놀드가 해결해주고 공유해주시라 믿습니다!!
export function throttle() {} | ||
export function clickOutside( | ||
dom: HTMLElement, | ||
func: (...args: any[]) => void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(...args: any[]) => void
이렇게 생긴 함수타입이 계속 재사용되는데 타입으로 하나 분리하셔서 재사용하시는거 어떠신가요?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋아요!
src/index.ts
Outdated
return (...args: any[]) => { | ||
if (!timer) { | ||
timer = setTimeout(() => { | ||
timer = null; | ||
func(...args); | ||
}, wait); | ||
} | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
리턴되는 함수의 args 가 결국 func
매개변수의 args 로 들어가네요!
그렇다면 확실하게 두 args 타입을 어떻게든 일치시켜보는거 어떠신가요 !!
저라면 아래와 같이 할 것 같아요
return (...args: any[]) => { | |
if (!timer) { | |
timer = setTimeout(() => { | |
timer = null; | |
func(...args); | |
}, wait); | |
} | |
}; | |
} | |
export function throttle<T extends (...args: any[]) => void>( | |
func: T, | |
wait: number | |
): (...args: Parameters<T>) => void { | |
let timer: ReturnType<typeof setTimeout> | null = null; | |
return (...args: Parameters<T>) => { | |
if (!timer) { | |
timer = setTimeout(() => { | |
timer = null; | |
func(...args); | |
}, wait); | |
} | |
}; | |
} | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이것도 어렵네요 ㅋㅋㅋㅋㅋㅋㅋㅋㅋ 호프 옆에서 물어보면서 고칠게요!
func: T, | ||
wait: number | ||
): (...args: any[]) => void { | ||
let timer: ReturnType<typeof setTimeout> | null = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ReturnType 이렇게 활용하는군요! 배워갑니다 👍
__tests__/type.test.ts
Outdated
expectType<void>($button.show()); | ||
|
||
expectType<void>($button.hide()); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
음 리턴타입에 대한 테스트를 진행해주셨네요!
expectType<(array: number[]) => number[]>(_.shuffle<number>);
저는 위처럼 함수 타입 자체를 테스트해주었는데요, 뭐가 더 좋은방법일까요 ? 저도 잘 모르겠네요ㅎㅎ
아니면 둘다 해주는게 좋을까요?
제네릭에 들어오는 타입에 따라서 반환타입이 달라지는 경우가 있어서 함수 타입 자체를 테스트하는게 좋다구 생각했어요. 근데 지금 생각하니 반환타입만 체크해도 충분할 것 같기도..?
아놀드의 생각은 어떠신가요 ??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저는 반환 타입만 해도 충분하다고 생각합니다!
함수 타입 테스트는 1은 1이냐? 라고 테스트 하는 격 같아요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
음 그렇네요! 저는 함수타입테스트를 했는데 아놀드말을 들어보니 그런것같아요.
소중한 의견 감사합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수정해주신 부분 다 확인했습니다 아놀드~~
코드리뷰 하면서 많이 얘기도 나누고 많이 배워서 너무 즐거웠어요 ㅎㅎ
아놀드의 말씀 잊지않을게요!!
제안 드린것도 빠르게 잘 반영해주셔서 감사합니다ㅎㅎ
이번 미션 넘 수고하셨어요! 터놓고 화이팅!
🔥 팀 미션 적용 결과
본 미션을 수행하며 경험, 영감, 학습한 내용을 팀 미션에 전파해주세요.
✅ 요구사항 구현 확인
DOM 유틸
유틸
🧐 공유
/_ 작업하면서 든 생각, 질문, 새롭게 학습하거나 시도해본 내용 등등 공유할 사항이 있다면 자유롭게 적어주세요 _/
https://www.npmjs.com/package/ternoko-utils-type << npm 링크
Valueof
라는 타입을 npm에 배포하여 팀에 적용하였습니다.처음 npm에 배포도 해보고 직접 install해서 사용해보니 너무 뿌듯했습니다~~