Vue Property Decorator를 사용하여 Vue 2의 유형 부족 문제 해결
예를 들어 다음 Vue 구성 요소를 살펴보겠습니다.
// SimpleCounter.vue
<template>
{{ value }}
</template>
<script lang="ts">
@Component
export default class SimpleCounter extends Vue {
private value: number = 0;
@Prop() step!: number;
@Prop({ default: 0 }) startAt!: number;
created() {
this.value = this.startAt;
}
increment() {
this.value += this.step;
}
}
</script>
그리고 다음 상위 구성요소(오류에 주의하세요!):
// App.vue
<template>
<!-- There should be an error here, "potato" isn't a number! -->
<simple-counter step="potato">
</template>
Vue 2는 컴파일 타임에 이 오류를 방지할 방법이 없습니다.
Flare에서는 다음을 통해 한동안 이 문제를 해결해 왔습니다.
// SimpleCounter.ts
// This file exports an interface that is used by all Simplecounter users.
// The interface has to be defined by hand, but at least it allows for
// validating that all users of the component are updated when we update
// the interface.
export interface SimpleCounterProps {
step: number;
startAt?: number;
};
// App.vue
<template>
<simple-counter v-bind="simpleCounterProps" />
</template>
<script>
@Component
class App extends Vue {
get simpleCounterProps(): SimpleCounterProps {
// We couldn’t make a mistake here.
// Typescript would warn us.
return {
step: 10,
};
}
}
</script>
그러나 인터페이스를 수동으로 선언해야 하고 인터페이스와 실제 구성 요소 간에 불일치가 있을 수 있기 때문에 이는 이상적이지 않습니다. 구성 요소를 수정하는 개발자는 잠재적으로 인터페이스 업데이트를 잊을 수 있으며 이로 인해 버그가 발생할 가능성이 높습니다.
해결책은 Vue 3를 사용하여 구성 요소 자체에서 직접 인터페이스를 파생시켜 단일 정보 소스를 갖는 것입니다. 이것은 구성 요소의 클래스를 취하고 해당 속성에 대한 인터페이스를 출력하는 일반 유틸리티 유형의 형태로 수행할 수 있습니다:
PropsOf<SimpleCounter>
.라이브러리
Vue Property Decorators
에는 클래스 속성을 소품으로 자동 할당하는 데코레이터Prop
가 있습니다. 다음 구문을 사용하여 기본값을 props로 설정할 수도 있습니다: @Prop({ default: 'hey' })
.이를 통해 구성 요소 내부에서 엄격하게 정의된(선택 사항이 아닌) 속성을 가질 수 있으며 여전히 상위 구성 요소의 선택적 속성을 수락할 수 있습니다.
클래스 추론 인터페이스를 사용하여 속성을 입력한다는 아이디어가 있었지만
$refs
및 $slots
와 같은 속성으로 많은 Vue 내부를 얻습니다.이를 제거하는 좋은 방법은
Vue
의 키를 생략하는 것입니다.이것은 약간 더 낫지만 여전히 자동 완성에서 모든 구성 요소 기능을 얻습니다. 이는 좋지 않습니다. props와 함수를 별도로 정의할 수 있다면 어떨까요? 해 봅시다!
// SimpleCounter.vue
<template>
{{ value }}
</template>
<script lang="ts">
@Component
class SimpleCounterProps extends Vue {
@Prop() step!: number;
@Prop({ default: 0 }) start!: number;
}
@Component
export default class SimpleCounter extends SimpleCounterProps {
private value: number = 0;
created() {
this.value = this.start;
}
increment() {
this.value += this.step;
}
}
</script>
이제 유일한 속성에 대한 인터페이스를 얻을 수 있는 간단한 방법이 있습니다. 네, 그렇습니다. 하지만 그렇지 않습니다. 유형은 아직 완전히 정확하지 않습니다.
보시다시피
step
는 올바르게 입력되었지만 start
는 선택적 속성으로 정의되지 않았습니다. 여기서 우리가 찾고 있는 것은 단순히 start?
대신에 start
를 갖는 것입니다. 속성 선언을 두 개의 다른 클래스로 분할하여 이를 수행할 수 있습니다. 첫 번째 클래스에는 필수 속성이 포함되고 두 번째 클래스에는 선택적 속성이 포함됩니다.// SimpleCounter.vue
<template>
{{ value }}
</template>
<script lang="ts">
@Component
class SimpleCounterRequiredProps extends Vue {
@Prop() step!: number;
}
@Component
class SimpleCounterOptionalProps extends Vue {
@Prop({ default: 0 }) start!: number;
}
@Component
export default class SimpleCounter extends Mixins(RequiredProps, OptionalProps) {
private value: number = 0;
created() {
this.value = this.start;
}
increment() {
this.value += this.step;
}
}
</script>
이렇게 하면 사용자 정의 유틸리티 유형을 사용하여 올바른 유형을 쉽게 파생시킬 수 있습니다.
// utilities.ts
type PropsOf<RequiredProps extends Vue, OptionalProps extends Vue> = Omit<Required<RequiredProps> & Partial<OptionalProps>, keyof Vue>;
마지막으로 파생된 인터페이스를 내보내겠습니다.
// SimpleCounter.vue
// ...
export type SimpleCounterProps = PropsOf<SimpleCounterRequiredProps, SimpleCounterOptionalProps>;
// ...
이제 다른 구성 요소의 속성 유형을 가져올 수 있으며 우리가 찾고 있던 것을 정확하게 얻을 수 있습니다.
🎉🎉🎉
단일 매개변수와 함께
PropsOf<SimpleCounter>
유형을 사용할 수 있으면 정말 좋았을 텐데 아직 이를 달성할 수 있는 방법을 찾지 못했습니다.
Reference
이 문제에 관하여(Vue Property Decorator를 사용하여 Vue 2의 유형 부족 문제 해결), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/flare/working-around-vue-2s-lack-of-types-using-vue-property-decorator-24e5텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)