Skip to content
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

[WIP] fix: fix issues with Vue's typings in SFC format #816

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions docs/framework/vue/quick-start.md
Original file line number Diff line number Diff line change
@@ -3,12 +3,6 @@ id: quick-start
title: Quick Start
---

> There is a bug in Vue's TypeScript support that's impacting our types that you'll likely run into:
>
> https://github.com/vuejs/language-tools/issues/3782
>
> Please give it a thumbs up, but _do not reply with comments such as "+1" or "When will this be fixed?", as such comments are unhelpful and rude_.

The bare minimum to get started with TanStack Form is to create a form and add a field. Keep in mind that this example does not include any validation or error handling... yet.

```vue
2 changes: 1 addition & 1 deletion examples/lit/simple/package.json
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
"lit": "^3.1.1"
},
"devDependencies": {
"vite": "^5.1.4"
"vite": "^5.3.3"
},
"browserslist": {
"production": [
6 changes: 3 additions & 3 deletions examples/lit/ui-libraries/package.json
Original file line number Diff line number Diff line change
@@ -9,12 +9,12 @@
"test:types": "tsc"
},
"dependencies": {
"@material/web": "^1.0.0",
"@tanstack/lit-form": "^0.25.2",
"lit": "^3.1.1",
"@material/web": "^1.0.0"
"lit": "^3.1.1"
},
"devDependencies": {
"vite": "^5.1.4"
"vite": "^5.3.3"
},
"browserslist": {
"production": [
2 changes: 1 addition & 1 deletion examples/react/array/package.json
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.0",
"vite": "^5.1.4"
"vite": "^5.3.3"
},
"browserslist": {
"production": [
4 changes: 2 additions & 2 deletions examples/react/query-integration/package.json
Original file line number Diff line number Diff line change
@@ -9,16 +9,16 @@
"test:types": "tsc"
},
"dependencies": {
"@tanstack/react-query": "^5.32.0",
"@tanstack/react-form": "^0.25.2",
"@tanstack/react-query": "^5.32.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.0",
"vite": "^5.1.4"
"vite": "^5.3.3"
},
"browserslist": {
"production": [
2 changes: 1 addition & 1 deletion examples/react/simple/package.json
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.0",
"vite": "^5.1.4"
"vite": "^5.3.3"
},
"browserslist": {
"production": [
2 changes: 1 addition & 1 deletion examples/react/tanstack-start/package.json
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.0",
"typescript": "5.4.2",
"vite": "^5.1.4",
"vite": "^5.3.3",
"vite-tsconfig-paths": "^4.3.2"
}
}
2 changes: 1 addition & 1 deletion examples/react/ui-libraries/package.json
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.7",
"typescript": "5.4.2",
"vite": "^5.1.4"
"vite": "^5.3.3"
},
"browserslist": {
"production": [
2 changes: 1 addition & 1 deletion examples/react/valibot/package.json
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.0",
"vite": "^5.1.4"
"vite": "^5.3.3"
},
"browserslist": {
"production": [
2 changes: 1 addition & 1 deletion examples/react/yup/package.json
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.0",
"vite": "^5.1.4"
"vite": "^5.3.3"
},
"browserslist": {
"production": [
2 changes: 1 addition & 1 deletion examples/react/zod/package.json
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.0",
"vite": "^5.1.4"
"vite": "^5.3.3"
},
"browserslist": {
"production": [
2 changes: 1 addition & 1 deletion examples/solid/array/package.json
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
},
"devDependencies": {
"typescript": "5.4.2",
"vite": "^5.1.4",
"vite": "^5.3.3",
"vite-plugin-solid": "^2.10.1"
}
}
2 changes: 1 addition & 1 deletion examples/solid/simple/package.json
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
},
"devDependencies": {
"typescript": "5.4.2",
"vite": "^5.1.4",
"vite": "^5.3.3",
"vite-plugin-solid": "^2.10.1"
}
}
2 changes: 1 addition & 1 deletion examples/solid/valibot/package.json
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
},
"devDependencies": {
"typescript": "5.4.2",
"vite": "^5.1.4",
"vite": "^5.3.3",
"vite-plugin-solid": "^2.10.1"
}
}
2 changes: 1 addition & 1 deletion examples/solid/yup/package.json
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
},
"devDependencies": {
"typescript": "5.4.2",
"vite": "^5.1.4",
"vite": "^5.3.3",
"vite-plugin-solid": "^2.10.1"
}
}
2 changes: 1 addition & 1 deletion examples/solid/zod/package.json
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
},
"devDependencies": {
"typescript": "5.4.2",
"vite": "^5.1.4",
"vite": "^5.3.3",
"vite-plugin-solid": "^2.10.1"
}
}
8 changes: 4 additions & 4 deletions examples/vue/array/package.json
Original file line number Diff line number Diff line change
@@ -11,12 +11,12 @@
},
"dependencies": {
"@tanstack/vue-form": "^0.25.2",
"vue": "^3.3.4"
"vue": "^3.4.31"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue": "^5.0.5",
"typescript": "5.4.2",
"vite": "^5.1.4",
"vue-tsc": "^2.0.6"
"vite": "^5.3.3",
"vue-tsc": "^2.0.26"
}
}
8 changes: 4 additions & 4 deletions examples/vue/simple/package.json
Original file line number Diff line number Diff line change
@@ -11,12 +11,12 @@
},
"dependencies": {
"@tanstack/vue-form": "^0.25.2",
"vue": "^3.3.4"
"vue": "^3.4.31"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue": "^5.0.5",
"typescript": "5.4.2",
"vite": "^5.1.4",
"vue-tsc": "^2.0.6"
"vite": "^5.3.3",
"vue-tsc": "^2.0.26"
}
}
3 changes: 0 additions & 3 deletions examples/vue/simple/src/App.vue
Original file line number Diff line number Diff line change
@@ -30,9 +30,6 @@ async function onChangeFirstName({ value }: { value: string }) {
"
>
<div>
<!-- Ignore errors in form.Field temporary due to a bug in Vue:-->
<!-- https://github.com/vuejs/language-tools/issues/3782 -->
<!-- @vue-ignore -->
<form.Field
name="firstName"
:validators="{
8 changes: 4 additions & 4 deletions examples/vue/valibot/package.json
Original file line number Diff line number Diff line change
@@ -13,12 +13,12 @@
"@tanstack/valibot-form-adapter": "^0.25.2",
"@tanstack/vue-form": "^0.25.2",
"valibot": "^0.35.0",
"vue": "^3.3.4"
"vue": "^3.4.31"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue": "^5.0.5",
"typescript": "5.4.2",
"vite": "^5.1.4",
"vue-tsc": "^2.0.6"
"vite": "^5.3.3",
"vue-tsc": "^2.0.26"
}
}
3 changes: 0 additions & 3 deletions examples/vue/valibot/src/App.vue
Original file line number Diff line number Diff line change
@@ -37,9 +37,6 @@ const onChangeFirstName = v.pipeAsync(
"
>
<div>
<!-- Ignore errors in form.Field temporary due to a bug in Vue:-->
<!-- https://github.com/vuejs/language-tools/issues/3782 -->
<!-- @vue-ignore -->
<form.Field
name="firstName"
:validators="{
8 changes: 4 additions & 4 deletions examples/vue/yup/package.json
Original file line number Diff line number Diff line change
@@ -12,13 +12,13 @@
"dependencies": {
"@tanstack/vue-form": "^0.25.2",
"@tanstack/yup-form-adapter": "^0.25.2",
"vue": "^3.3.4",
"vue": "^3.4.31",
"yup": "^1.3.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue": "^5.0.5",
"typescript": "5.4.2",
"vite": "^5.1.4",
"vue-tsc": "^2.0.6"
"vite": "^5.3.3",
"vue-tsc": "^2.0.26"
}
}
3 changes: 0 additions & 3 deletions examples/vue/yup/src/App.vue
Original file line number Diff line number Diff line change
@@ -36,9 +36,6 @@ const onChangeFirstName = yup
"
>
<div>
<!-- Ignore errors in form.Field temporary due to a bug in Vue:-->
<!-- https://github.com/vuejs/language-tools/issues/3782 -->
<!-- @vue-ignore -->
<form.Field
name="firstName"
:validators="{
8 changes: 4 additions & 4 deletions examples/vue/zod/package.json
Original file line number Diff line number Diff line change
@@ -12,13 +12,13 @@
"dependencies": {
"@tanstack/vue-form": "^0.25.2",
"@tanstack/zod-form-adapter": "^0.25.2",
"vue": "^3.3.4",
"vue": "^3.4.31",
"zod": "^3.22.4"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue": "^5.0.5",
"typescript": "5.4.2",
"vite": "^5.1.4",
"vue-tsc": "^2.0.6"
"vite": "^5.3.3",
"vue-tsc": "^2.0.26"
}
}
3 changes: 0 additions & 3 deletions examples/vue/zod/src/App.vue
Original file line number Diff line number Diff line change
@@ -39,9 +39,6 @@ const onChangeFirstName = z.string().refine(
"
>
<div>
<!-- Ignore errors in form.Field temporary due to a bug in Vue:-->
<!-- https://github.com/vuejs/language-tools/issues/3782 -->
<!-- @vue-ignore -->
<form.Field
name="firstName"
:validators="{
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -45,11 +45,11 @@
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^14.2.1",
"@testing-library/user-event": "^14.5.2",
"@testing-library/vue": "^8.0.2",
"@testing-library/vue": "^8.1.0",
"@types/node": "^20.9.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitest/coverage-istanbul": "^1.3.1",
"@vitest/coverage-istanbul": "^1.6.0",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.2",
"jsdom": "^24.0.0",
@@ -70,8 +70,8 @@
"typescript51": "npm:typescript@5.1",
"typescript52": "npm:typescript@5.2",
"typescript53": "npm:typescript@5.3",
"vite": "^5.1.4",
"vitest": "^1.3.1",
"vue": "^3.3.4"
"vite": "^5.3.3",
"vitest": "^1.6.0",
"vue": "^3.4.31"
}
}
6 changes: 3 additions & 3 deletions packages/react-form/package.json
Original file line number Diff line number Diff line change
@@ -72,10 +72,10 @@
"src"
],
"dependencies": {
"@remix-run/node": "^2.9.2",
"@tanstack/form-core": "workspace:*",
"@tanstack/react-store": "^0.5.0",
"decode-formdata": "^0.7.5",
"@remix-run/node": "^2.9.2"
"decode-formdata": "^0.7.5"
},
"devDependencies": {
"@tanstack/start": "^1.42.1",
@@ -84,7 +84,7 @@
"@vitejs/plugin-react": "^4.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"vite": "^5.1.4"
"vite": "^5.3.3"
},
"peerDependencies": {
"@tanstack/start": "^1.40.1",
2 changes: 1 addition & 1 deletion packages/solid-form/package.json
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@
},
"devDependencies": {
"solid-js": "^1.7.8",
"vite": "^5.1.4",
"vite": "^5.3.3",
"vite-plugin-solid": "^2.10.1"
},
"peerDependencies": {
8 changes: 4 additions & 4 deletions packages/vue-form/package.json
Original file line number Diff line number Diff line change
@@ -57,11 +57,11 @@
"@tanstack/vue-store": "^0.5.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"vite": "^5.1.4",
"vue": "^3.3.4"
"@vitejs/plugin-vue": "^5.0.5",
"vite": "^5.3.3",
"vue": "^3.4.31"
},
"peerDependencies": {
"vue": "^3.3.0"
"vue": "^3.4.0"
}
}
109 changes: 62 additions & 47 deletions packages/vue-form/src/useField.tsx
Original file line number Diff line number Diff line change
@@ -2,9 +2,69 @@ import { FieldApi } from '@tanstack/form-core'
import { useStore } from '@tanstack/vue-store'
import { defineComponent, onMounted, onUnmounted, watch } from 'vue'
import type { DeepKeys, DeepValue, Validator } from '@tanstack/form-core'
import type { Ref, SetupContext, SlotsType } from 'vue'
import type { EmitsOptions, Ref, SetupContext, SlotsType } from 'vue'
import type { UseFieldOptions } from './types'

const DefineFieldFn = <
TParentData,
TFormValidator extends
| Validator<TParentData, unknown>
| undefined = undefined,
>() =>
defineComponent(
<
TName extends DeepKeys<TParentData>,
TFieldValidator extends
| Validator<DeepValue<TParentData, TName>, unknown>
| undefined = undefined,
TData extends DeepValue<TParentData, TName> = DeepValue<
TParentData,
TName
>,
>(
_props: Omit<
FieldComponentProps<
TParentData,
TName,
TFieldValidator,
TFormValidator,
TData
>,
'form'
>,
_ctx: SetupContext<
EmitsOptions,
SlotsType<{
default: {
field: FieldApi<
TParentData,
TName,
TFieldValidator,
TFormValidator,
TData
>
state: FieldApi<
TParentData,
TName,
TFieldValidator,
TFormValidator,
TData
>['state']
}
}>
>,
) =>
() =>
null,
)

export type FieldComponent<
TParentData,
TFormValidator extends
| Validator<TParentData, unknown>
| undefined = undefined,
> = ReturnType<typeof DefineFieldFn<TParentData, TFormValidator>>

interface VueFieldApi<
TParentData,
TFormValidator extends
@@ -102,7 +162,7 @@ export function useField<
return { api: fieldApi, state: fieldState } as const
}

type FieldComponentProps<
export type FieldComponentProps<
TParentData,
TName extends DeepKeys<TParentData>,
TFieldValidator extends
@@ -114,51 +174,6 @@ type FieldComponentProps<
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
> = UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>

export type FieldComponent<
TParentData,
TFormValidator extends
| Validator<TParentData, unknown>
| undefined = undefined,
> = <
TName extends DeepKeys<TParentData>,
TFieldValidator extends
| Validator<DeepValue<TParentData, TName>, unknown>
| undefined = undefined,
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
>(
fieldOptions: Omit<
FieldComponentProps<
TParentData,
TName,
TFieldValidator,
TFormValidator,
TData
>,
'form'
>,
context: SetupContext<
{},
SlotsType<{
default: {
field: FieldApi<
TParentData,
TName,
TFieldValidator,
TFormValidator,
TData
>
state: FieldApi<
TParentData,
TName,
TFieldValidator,
TFormValidator,
TData
>['state']
}
}>
>,
) => any

export const Field = defineComponent(
<
TParentData,
31 changes: 19 additions & 12 deletions packages/vue-form/src/useForm.tsx
Original file line number Diff line number Diff line change
@@ -7,6 +7,21 @@ import type { NoInfer } from '@tanstack/vue-store'
import type { EmitsOptions, Ref, SetupContext, SlotsType } from 'vue'
import type { FieldComponent, UseField } from './useField'

const SubscribeFn = <TFormData,>() =>
defineComponent(
<TSelected = NoInfer<FormState<TFormData>>,>(
_props: {
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected
},
_ctx: SetupContext<
EmitsOptions,
SlotsType<{ default: NoInfer<FormState<TFormData>> }>
>,
) =>
() =>
null,
)

interface VueFormApi<
TFormData,
TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
@@ -16,15 +31,7 @@ interface VueFormApi<
useStore: <TSelected = NoInfer<FormState<TFormData>>>(
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,
) => Readonly<Ref<TSelected>>
Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(
props: {
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected
},
context: SetupContext<
EmitsOptions,
SlotsType<{ default: NoInfer<FormState<TFormData>> }>
>,
) => any
Subscribe: ReturnType<typeof SubscribeFn<TFormData>>
}

export function useForm<
@@ -49,7 +56,7 @@ export function useForm<
name: 'APIField',
inheritAttrs: false,
},
)
) as never
extendedApi.useField = (props) => {
const field = useField({ ...props, form: api })
return field
@@ -60,15 +67,15 @@ export function useForm<
extendedApi.Subscribe = defineComponent(
(props, context) => {
const allProps = { ...props, ...context.attrs }
const selector = allProps.selector ?? ((state) => state)
const selector = allProps.selector ?? ((state: never) => state)
const data = useStore(api.store as never, selector as never)
return () => context.slots.default!(data.value)
},
{
name: 'Subscribe',
inheritAttrs: false,
},
)
) as never

return extendedApi
})()
5,858 changes: 4,076 additions & 1,782 deletions pnpm-lock.yaml

Large diffs are not rendered by default.