똑같은 삽질은 2번 하지 말자
Typescript + Vue 본문
Typescript 로 마이그레이션 하면서 기록하고 싶은것들
1. 결과값(JSON)이 비었을 경우 해당 결과를 빈 배열로 초기화 하고 싶을때
2. debugger 중단점 말고 키워드로 디버깅하는 방법 (꽤 유용할꺼 같아 적어놓음)
3. computed 의 반환타입은 무조건 넣어줘야 올바른 추론이 이루어질 수 있다.
computed의 사용용도?
- 간결하고 직관적인 템플릿 표현식
- 조건에 따라 HTML 클래스를 추가/변경할 때
- Vuex의 state값에 접근할 때
- 다국어 라이브러리에도 활용 가능
4. 자동 추론.. 타입을 정의해야하는 필요성에 대해 좀더 깊게 생각해보자
밑의 경우는 fetch의 리턴타입을 정의함으로써 sort안 내부 메소드의 param의 자동추론이 이루어지는 케이스인데,
sort 메소드의 param은 타입정의가 필요없어지는게 포인트!
5. (vue-cli)를 이용한 $ vue add typescript 는 안하는게 좋다.. 자동으로 파일내용을 변경해버리는게 많기 때문에
6. Type Alias와 Interface의 차이점
Type Alias(타입 별칭)와 Interface를 보면 거의 똑같은 기능을 하고 있는것 처럼 보이는데,
그런데 큰 차이가 하나 있다. Interface는 선언 병합이 가능하지만, Type Alias는 그렇지 않다는것.
Interface의 선언 병합(extends)
Interface는 동일한 이름으로 여러 번 선언해도 컴파일 시점에 아래처럼 합칠 수 있습니다.
이런 동작을 선언 병합(Declaration Merging)이라 한다. (vue의 인터페이스에 vuex가 선언병합을 이용해 Store타입을 넣고있다.)
// vue/type/vue
export interface Vue {
readonly $el: Element;
readonly $options: ComponentOptions<Vue>;
readonly $parent: Vue;
readonly $root: Vue;
readonly $children: Vue[];
readonly $refs: { [key: string]: Vue | Element | (Vue | Element)[] | undefined };
readonly $slots: { [key: string]: VNode[] | undefined };
readonly $scopedSlots: { [key: string]: NormalizedScopedSlot | undefined };
readonly $isServer: boolean;
readonly $data: Record<string, any>;
readonly $props: Record<string, any>;
readonly $ssrContext: any;
...이하 생략
}
// vuex/type/vue
declare module "vue/types/vue" {
interface Vue {
$store: Store<any>;
}
}
https://yamoo9.gitbook.io/typescript/interface/extends
TypeScript 팀의 의도
TypeScript 팀은 개방-폐쇄 원칙(OCP, Open-Closed Principle) (소프트웨어 개체(클래스, 모듈, 함수 등등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다'는 프로그래밍 원칙)에 따라 확장에 열려있는 JavaScript 객체의 동작 방식과 비슷하게 연결하도록 Interface를 설계했다.
그래서 TypeScript 팀은 가능한 Type Alias보단 Interface를 사용하고, 합 타입 혹은 튜플 타입을 반드시 써야 되는 상황이면 Type Alias를 사용하도록 권장하고 있습니다.
음.. 타입 별칭은 인터섹션(&)을 이용해서 확장 비스무레한 것(?)을 할 수 있기때문에 어느쪽을 쓰든 솔직히 상관없다는 느낌이 아직까지는 강하다... 물론 타입팀의 의도처럼 인터페이스를 기본베이스로 가져가는게 좋을듯하다.. 와 닿지는 않지만 일단 그러려니하고 넘어가자.
declare module에 대해서(ts, js 컴파일내용도 들어있다.)
7. Store의 타입 추론이 안되는 이유
위의 사진처럼 나는 state안에 여러가지의 배열들을 선언 빈값으로 초기화까지 해주었지만
밑의 사진처럼 state에 뭐가 있는건지 전혀 추론이 안되고있다.
밑의 스샷은 node_modules안의 vuex의 타입인데 vuex의 라이브러리 타입구조상 default로 any형이 들어가고 있기때문에 따로 Generic을 넘겨주지 않는이상 추론이 이루어질 수 없는 구조이다. ㅠ
위의 any 부분을 건들면 모든 컴포넌트에서 타입추론이 잘 이루어지더라.. 물론 실무에서 활용할 수 있는 방법은 아니지만,
이런것도 있다하고 넘기면 될 것 같다.
8. ref 속성 타입 정의 방법
<template>
<div>
<div ref="my"></div>
</div>
</template>
<script lang="ts">
import Vue, { VueConstructor } from "vue";
export default (Vue as VueConstructor<Vue & { $refs: { my: HTMLDivElement } }>).extend({
mounted() {
this.$refs.my; // HTMLDivElement
}
});
</script>
타입 인터섹션을 이용해서 my: HTMLDivElement가 $refs 타입안에 확장되어 추론되게끔 한다.
이러한 부분들도 Vue3이되면 좀더 쉽게 타입을 씌울 수 있게 해주었을꺼같은 느낌이드는데 나중에 한번 찾아보자.
9. Event타입 커스텀하기
export namespace VueEvent {
export interface Input<T extends EventTarget> extends InputEvent {
target: T;
}
}
Event -> target 속성이 정의되어 있다 그래서 제네릭으로 target속성의 타입을 재정의 하려고 하면 에러가 나기때문에 EventTarget을 상속받아서 해야한다.
↓
UIEvent
↓
InputEvent
↓
VueEvent
'Vue' 카테고리의 다른 글
vue(vue-cli)에서 component preload prefetch 기능 끄기 (0) | 2021.11.03 |
---|---|
vue-cli 와 webpack 설정 (0) | 2021.11.03 |
Nuxt 정리 No.4 (Nuxt LifeCycle, nuxtServerInit 정리) (0) | 2021.10.09 |
Nuxt 에서 fontawesome 도입하기 (0) | 2021.08.28 |
Nuxt + tailwind 할때 tailwind.config.js 설정 (0) | 2021.08.15 |