일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 웹
- 타입스크립트
- 파이썬
- AWS
- next.js
- 자바스크립트
- react
- 클라우드
- 백준
- 솔리디티
- JavaScript
- 프론트엔드
- TypeScript
- kubernetes
- 컴퓨터공학
- 이슈
- 알고리즘
- HTML
- 쿠버네티스
- 이더리움
- CSS
- VUE
- 가상화
- k8s
- es6
- 백엔드
- docker
- 리액트
- 블록체인
- BFS
- Today
- Total
즐겁게, 코드
vee-validate에 타입스크립트 적용하기 (@vee-validate/yup) 본문
공식 문서에 있는 간단한 내용이긴 하지만 기록해두면 좋을 것 같아 정리해 보았다.
React-Hook-Form (RHF)의 register
함수와는 달리, vee-validate의 defineField
함수는 기본적으로 타입 추론을 제시하지 않는다.
이것이 무슨 말인가 하면...
const { values, errors, defineField } = useForm({
validationSchema,
});
const validationSchema = yup.object({
startDate: yup
.date()
.required('날짜를 입력해 주세요')
.max(yup.ref('endDate'), '시작일을 종료일 이전으로 입력해 주세요'),
endDate: yup.date().required('날짜를 입력해 주세요'),
});
// ❌ 별도의 설정이 없다면 '<스키마의 키 값>' 은 타입스크립트에 의해 제안되지 않는다.
const [startDate] = defineField('<스키마의 키 값>');
vee-validate가 키 값을 추론하기 위해서는 yup이 타입스크립트 지원을 받을 수 있도록 @vee-validate/yup
패키지를 추가로 설치할 수 있다.
# @vee-validate/yup 패키지 설치
npm install @vee-validate/yup
// toTypedSchema 는 yup이 vee-validate에 타입 추론을 제공할 수 있도록 도와준다.
import { toTypedSchema } from '@vee-validate/yup';
const validationSchema = toTypedSchema(yup.object({
startDate: yup
.date()
.required('날짜를 입력해 주세요')
.max(yup.ref('endDate'), '시작일을 종료일 이전으로 입력해 주세요'),
endDate: yup.date().required('날짜를 입력해 주세요'),
}));
const [startDate] = defineField(''); // ✅ defineField 함수 인자의 타입이 추론된다.
만약 yup이나 zod 등의 검증 라이브러리를 사용하지 않거나, 라이브러리를 추가로 설치하는 것이 마음에 들지 않는다면 타입을 직접 제네릭으로 전달할 수도 있다.
const validationSchema = yup.object({
startDate: yup
.date()
.required('날짜를 입력해 주세요')
.max(yup.ref('endDate'), '시작일을 종료일 이전으로 입력해 주세요'),
endDate: yup.date().required('날짜를 입력해 주세요'),
});
// toTypedSchema를 사용하지 않고, useForm에 직접 제네릭 타입을 정의할 수도 있다.
const { values, errors, defineField } = useForm<{
startDate: string;
endDate: string;
}>({
validationSchema,
});
const [startDate] = defineField(''); // ✅ defineField 함수 타입이 추론된다.
의도치 않게(?) Vue 개발을 주로 하게 되면서 React의 RHF을 사용하지 못한다는 점이 크게 아쉬웠는데, 생각보다 vee-validate를 사용한 개발 경험에 만족하는 중이다.
번외
defineField("키")
함수는 Path<TValues>
타입을 "키" 의 타입으로 기대한다.
그런데 useForm이 제네릭으로 받는 TValues
타입이 어떤 마법을 거쳐 Path<TValues>
타입으로 전환되어 전달될지가 궁금했다.
// useForm()
// TValues 타입을 제네릭 첫 번째 인자로 받는다.
declare function useForm<TValues extends GenericObject = GenericObject, TOutput extends GenericObject = TValues, TSchema extends FormSchema<TValues> | TypedSchema<TValues, TOutput> = FormSchema<TValues> | TypedSchema<TValues, TOutput>>(opts?: FormOptions<TValues, TOutput, TSchema>): FormContext<TValues, TOutput>;
// defineField()
// Path<TValues> 타입을 제네릭 첫 번째 인자로 받는다.
defineField<TPath extends Path<TValues>, TValue = PathValue<TValues, TPath>, TExtras extends GenericObject = GenericObject>(path: MaybeRefOrGetter<TPath>, config?: Partial<InputBindsConfig<TValue, TExtras>> | LazyInputBindsConfig<TValue, TExtras>): [Ref<TValue>, Ref<BaseFieldProps & TExtras>];
// 둘의 타입이 다른데, 어떻게 TValues 타입이 Path<TValues> 타입으로 전환되는 걸까?
아직 긴 코드를 분석하는 능력은 부족해 GPT에 질의했더니 FormContext
의 존재를 알게 되었다.
📄 질문 링크 : https://chatgpt.com/share/6763b59d-dd20-8008-89ca-6783e29d4c8d
또 toTypedSchema
를 살펴보면 스키마를 인자로 받아 TypedSchema
로 캐스팅해 리턴한다.
toTypedSchema<TSchema extends Schema, TOutput = InferType<TSchema>, TInput = PartialDeep<TOutput>>(
yupSchema: TSchema,
opts: ValidateOptions = { abortEarly: false },
): TypedSchema<TInput, TOutput>
toTypedSchema
함수를 통해 validationSchema
에 TypedSchema
타입을 전달할 수 있게 되면 validationSchema
는 TypedSchema<TValues, TOutput>
이 되고, 제네릭에 전달된 TValues
타입이 defineFields
에 전달되는 것으로 보인다.
// useForm 컴포저블의 FormOptions 중
validationSchema?: MaybeRef<TSchema extends TypedSchema ? TypedSchema<TValues, TOutput> : any>;
// * TValues는 기본적으로 Record<string, any> 타입이다.
오픈소스를 사용할 때 원리를 알고 쓰려 노력하는 중인데, 타입스크립트 관문을 통과해야 하는게 쉽지 않은 것 같아 더 공부해야겠다. 🙇♂️
'🎨 프론트엔드 > Vue.js' 카테고리의 다른 글
[Vue] inject-provide 패턴 조금 더 잘 써보기 (0) | 2024.11.19 |
---|---|
Vue 3에서 페이지 전환 애니메이션 추가하기 (0) | 2023.12.24 |
Vuex의 namespaced module 활용하기 (0) | 2022.04.04 |
v-show와 v-if 지시자의 차이 (0) | 2021.08.18 |
Vue 컴포넌트에서 name 속성을 명시하는 이유 (0) | 2021.05.24 |