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

feat(types): make types on functions extend off the base classes generics #1268

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

s-hoff
Copy link

@s-hoff s-hoff commented Mar 11, 2025

The goal here is to eventually allow a withForm component to accept "extending" forms, or those which are bigger then what they know about but do contain what they need.
I suspect that even an alternative solution to withForm would still need those changes to work.

While looking at the TS error that comes when trying this, I noticed that it was always about the types in the functions but never about the object attributes. So after some experimenting, it turns out that this fails:

type Test<T> = {
  defaultValues: T
  fun: (props: { value: T }) => {}
}
const t: Test<{ firstName: string }> =
  {} as Test<{ firstName: string, lastName: string }>

While this works:

type Test2<T> = {
  defaultValues: T,
  fun: <TF extends T = T>(props: { value: TF }) => void
}

// ist fine, the actual type has all that was asked for and then some
const t2: Test2<{ firstName: string }> =
  {} as Test2<{ firstName: string, lastName: string }>

and still ensures that firstName is included on t2. The main idea is unless props.value only extends T, TypeScript checks the equality both ways. If it does extend T, the checking becomes unidirectional.

This obviously still needs a lot of work to be done as most likely all function signatures would have to be changed in such a matter and more type errors will come up along the way.

But at least this works to prove the concept:

const f1 = {} as FormOptions<
  { firstName: string, lastName: string },
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined
>

const f2: FormOptions<
  { firstName: string },
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
  undefined
> = f1

with surprisingly few errors in FieldApi.ts to track down.

Once its all the way done, the inference should still work just fine.

…ric instead of equal to them

Basically, this fails:
```ts
type Test<T> = {
  defaultValues: T
  fun: (props: { value: T }) => {}
}
const t: Test<{ firstName: string }> =
  {} as Test<{ firstName: string, lastName: string }>
```

While this works:
```ts
type Test2<T> = {
  defaultValues: T,
  fun: <TF extends T = T>(props: { value: TF }) => void
}

// ist fine, the actual type has all that was asked for and then some
const t2: Test2<{ firstName: string }> =
  {} as Test2<{ firstName: string, lastName: string }>
```

and still ensures that `firstName` is included on t2.
The main idea is unless `props.value` only extends T, TypeScript checks the equality both ways.
If it does extend T, the checking becomes unidirectional
@harry-whorlow harry-whorlow changed the title Draft: feat(types): make types on functions extend off the base classes generics feat(types): make types on functions extend off the base classes generics Mar 12, 2025
@harry-whorlow harry-whorlow marked this pull request as draft March 12, 2025 11:10
@harry-whorlow
Copy link
Contributor

@s-hoff draft is more a type of pr than the title 🤟, just updated the pr for you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants