Skip to content

Commit

Permalink
fix: React TSC usage for 4.9 now works properly (#733)
Browse files Browse the repository at this point in the history
* chore: fix React TSC usage for 4.9

* chore: fix linting
  • Loading branch information
crutchcorn authored Jun 3, 2024
1 parent 5670725 commit 4879e32
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 29 deletions.
2 changes: 2 additions & 0 deletions packages/react-form/src/tests/useField.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ it('should type state.value properly', () => {
name="firstName"
children={(field) => {
assertType<'test'>(field.state.value)
return null
}}
/>
<form.Field
name="age"
children={(field) => {
assertType<84>(field.state.value)
return null
}}
/>
</>
Expand Down
9 changes: 9 additions & 0 deletions packages/react-form/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
FieldApiOptions,
Validator,
} from '@tanstack/form-core'
import type { FunctionComponent } from 'rehackt'

export type UseFieldOptions<
TParentData,
Expand All @@ -24,3 +25,11 @@ export type UseFieldOptions<
> & {
mode?: 'value' | 'array'
}

/**
* The return type of React.ReactNode appears to change between React 4.9 and 5.0
*
* This means that if we replace this type with React.ReactNode, there will be
* random typings the fail between React 4.9 and 5.0. This is a hack that resolves this issue.
*/
export type NodeType = ReturnType<FunctionComponent>
35 changes: 10 additions & 25 deletions packages/react-form/src/useField.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import React, { useState } from 'rehackt'
import React, { type FunctionComponent, useState } from 'rehackt'
import { useStore } from '@tanstack/react-store'
import { FieldApi, functionalUpdate } from '@tanstack/form-core'
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
import type { UseFieldOptions } from './types'
import type {
DeepKeys,
DeepValue,
Narrow,
Validator,
} from '@tanstack/form-core'
import type { NodeType, UseFieldOptions } from './types'
import type { DeepKeys, DeepValue, Validator } from '@tanstack/form-core'

declare module '@tanstack/form-core' {
// eslint-disable-next-line no-shadow
Expand Down Expand Up @@ -117,7 +112,7 @@ type FieldComponentProps<
TFormValidator,
TData
>,
) => any
) => NodeType
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>

export type FieldComponent<
Expand All @@ -143,9 +138,9 @@ export type FieldComponent<
TData
>,
'form'
>) => any
>) => NodeType

export function Field<
export const Field = (<
TParentData,
TName extends DeepKeys<TParentData>,
TFieldValidator extends
Expand All @@ -158,24 +153,14 @@ export function Field<
>({
children,
...fieldOptions
}: {
children: (
fieldApi: FieldApi<
TParentData,
TName,
TFieldValidator,
TFormValidator,
TData
>,
) => any
} & UseFieldOptions<
}: FieldComponentProps<
TParentData,
TName,
TFieldValidator,
TFormValidator,
TData
>) {
>): NodeType => {
const fieldApi = useField(fieldOptions as any)

return <>{functionalUpdate(children, fieldApi as any)}</>
}
return (<>{functionalUpdate(children, fieldApi as any)}</>) as never
}) satisfies FunctionComponent<FieldComponentProps<any, any, any, any, any>>
9 changes: 5 additions & 4 deletions packages/react-form/src/useForm.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { FormApi, functionalUpdate } from '@tanstack/form-core'
import { useStore } from '@tanstack/react-store'
import React, { type ReactNode, useState } from 'rehackt'
import React, { useState } from 'rehackt'
import { Field, type FieldComponent, type UseField, useField } from './useField'
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
import type { NoInfer } from '@tanstack/react-store'
import type { FormOptions, FormState, Validator } from '@tanstack/form-core'
import type { NodeType } from './types'

declare module '@tanstack/form-core' {
// eslint-disable-next-line no-shadow
Expand All @@ -27,8 +28,8 @@ declare module '@tanstack/form-core' {
@see {@link https://github.com/microsoft/TypeScript/issues/52786 | The bug report in `microsoft/TypeScript`}
*/
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected
children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode
}) => JSX.Element
children: ((state: NoInfer<TSelected>) => NodeType) | NodeType
}) => NodeType
}
}

Expand All @@ -41,7 +42,7 @@ export function useForm<
const [formApi] = useState(() => {
const api = new FormApi<TFormData, TFormValidator>(opts)
api.Field = function APIField(props) {
return <Field {...props} form={api} />
return (<Field {...props} form={api} />) as never
}
// eslint-disable-next-line react-hooks/rules-of-hooks
api.useField = (props) => useField({ ...props, form: api })
Expand Down

0 comments on commit 4879e32

Please sign in to comment.