Skip to content
This repository was archived by the owner on Oct 23, 2023. It is now read-only.

Commit 4daf9a4

Browse files
committed
feat: relax the typings when the as prop is not used to enhance autocomplete
1 parent 0e30dcc commit 4daf9a4

File tree

8 files changed

+49
-23
lines changed

8 files changed

+49
-23
lines changed

.changeset/gentle-shoes-tell.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@polymorphic-factory/solid': patch
3+
---
4+
5+
Fixed an issue where the typings for the as prop where to restrictive.

.changeset/purple-seahorses-matter.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@polymorphic-factory/preact': patch
3+
'@polymorphic-factory/react': patch
4+
---
5+
6+
Slightly relax the typings for the `as` prop when it is not used.

packages/preact/src/forwardRef.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ type MergeWithAs<
5050
* overriding props but also because somehow it is needed to get the props correctly,
5151
* Merge does clone the first object so that might have something to do with it.
5252
*/
53-
| Assign<DefaultProps, PermanentProps & { as?: Default }>
53+
| Assign<DefaultProps, PermanentProps & { as?: Default | ElementType }>
5454
| Assign<ComponentProps, PermanentProps & { as?: Component }>
5555
: never
5656

packages/preact/test/forward-ref.test.tsx

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createRef } from 'preact'
2-
import type { HTMLPolymorphicProps } from '../src'
2+
import type { ComponentWithAs, HTMLPolymorphicProps } from '../src'
33
import { polymorphicFactory, forwardRef } from '../src'
44
import { render } from '@testing-library/preact'
55

@@ -25,4 +25,11 @@ describe('forwardRef', () => {
2525
render(<ComponentUnderTest as="form" ref={ref} />)
2626
expect(ref.current).toBeInstanceOf(HTMLFormElement)
2727
})
28+
29+
it('should allow arbitrary components for the as prop', () => {
30+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
31+
const Comp = (_props: Record<never, never>) => null
32+
const CustomComp: ComponentWithAs<typeof Comp> = (props) => <poly.div as={Comp} {...props} />
33+
render(<CustomComp />)
34+
})
2835
})

packages/react/src/forwardRef.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ type MergeWithAs<
5555
* overriding props but also because somehow it is needed to get the props correctly,
5656
* Merge does clone the first object so that might have something to do with it.
5757
*/
58-
| Assign<DefaultProps, PermanentProps & { as?: Default }>
58+
| Assign<DefaultProps, PermanentProps & { as?: Default | ElementType }>
5959
| Assign<ComponentProps, PermanentProps & { as?: Component }>
6060
: never
6161

packages/react/test/forward-ref.test.tsx

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createRef } from 'react'
2-
import type { HTMLPolymorphicProps } from '../src'
2+
import type { ComponentWithAs, HTMLPolymorphicProps } from '../src'
33
import { polymorphicFactory, forwardRef } from '../src'
44
import { render } from '@testing-library/react'
55

@@ -25,4 +25,11 @@ describe('forwardRef', () => {
2525
render(<ComponentUnderTest as="form" ref={ref} />)
2626
expect(ref.current).toBeInstanceOf(HTMLFormElement)
2727
})
28+
29+
it('should allow arbitrary components for the as prop', () => {
30+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
31+
const Comp = (_props: Record<never, never>) => null
32+
const CustomComp: ComponentWithAs<typeof Comp> = (props) => <poly.div as={Comp} {...props} />
33+
render(<CustomComp />)
34+
})
2835
})

packages/solid/src/polymorphic-factory.tsx

+12-18
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
import {
2-
type ValidComponent,
3-
type Component,
4-
type JSX,
5-
type ComponentProps,
6-
splitProps,
7-
} from 'solid-js'
1+
import { type Component, type JSX, type ComponentProps, splitProps } from 'solid-js'
82
import { Dynamic } from 'solid-js/web'
93

104
type DOMElements = keyof JSX.IntrinsicElements
@@ -29,8 +23,8 @@ type DistributiveOmit<T, K extends keyof any> = T extends any ? Omit<T, K> : nev
2923
export type Assign<A, B> = DistributiveOmit<A, keyof B> & B
3024

3125
type MergeWithAs<
32-
Default extends ValidComponent,
33-
Component extends ValidComponent,
26+
Default extends ElementType,
27+
Component extends ElementType,
3428
PermanentProps extends Record<never, never>,
3529
DefaultProps extends Record<never, never>,
3630
ComponentProps extends Record<never, never>,
@@ -57,15 +51,15 @@ type MergeWithAs<
5751
* overriding props but also because somehow it is needed to get the props correctly,
5852
* Merge does clone the first object so that might have something to do with it.
5953
*/
60-
| Assign<DefaultProps, PermanentProps & { as?: Default }>
54+
| Assign<DefaultProps, PermanentProps & { as?: Default | ElementType }>
6155
| Assign<ComponentProps, PermanentProps & { as?: Component }>
6256
: never
6357

6458
export type ComponentWithAs<
65-
Component extends ValidComponent,
59+
Component extends ElementType,
6660
Props extends Record<never, never> = Record<never, never>,
6761
> = {
68-
<AsComponent extends ValidComponent = Component>(
62+
<AsComponent extends ElementType = Component>(
6963
props: MergeWithAs<
7064
Component,
7165
AsComponent,
@@ -80,21 +74,21 @@ export type HTMLPolymorphicComponents<Props extends Record<never, never> = Recor
8074
[Tag in DOMElements]: ComponentWithAs<Tag, Props>
8175
}
8276

83-
export type HTMLPolymorphicProps<T extends ValidComponent> = Omit<ComponentProps<T>, 'ref'> & {
84-
as?: ValidComponent
77+
export type HTMLPolymorphicProps<T extends ElementType> = Omit<ComponentProps<T>, 'ref'> & {
78+
as?: ElementType
8579
}
8680

8781
type PolymorphFactory<
8882
Props extends Record<never, never> = Record<never, never>,
8983
Options = never,
9084
> = {
91-
<T extends ValidComponent, P extends Record<never, never> = Props>(
85+
<T extends ElementType, P extends Record<never, never> = Props>(
9286
component: T,
9387
option?: Options,
9488
): ComponentWithAs<T, P>
9589
}
9690

97-
function defaultStyled(originalComponent: ValidComponent) {
91+
function defaultStyled(originalComponent: ElementType) {
9892
// any is required for the import('solid/web').ValidComponent typings:
9993
// eslint-disable-next-line @typescript-eslint/no-explicit-any
10094
return (props: ComponentProps<ComponentWithAs<any>>) => {
@@ -106,7 +100,7 @@ function defaultStyled(originalComponent: ValidComponent) {
106100
}
107101

108102
interface PolyFactoryParam<
109-
Component extends ValidComponent,
103+
Component extends ElementType,
110104
Props extends Record<never, never>,
111105
Options,
112106
> {
@@ -125,7 +119,7 @@ interface PolyFactoryParam<
125119
export function polymorphicFactory<
126120
Props extends Record<never, never>,
127121
Options = never,
128-
Component extends ValidComponent = ValidComponent,
122+
Component extends ElementType = ElementType,
129123
>({ styled = defaultStyled }: PolyFactoryParam<Component, Props, Options> = {}) {
130124
const cache = new Map<Component, ComponentWithAs<Component, Props>>()
131125

packages/solid/test/polymorphic-factory.test.tsx

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { render, screen } from 'solid-testing-library'
2-
import { type HTMLPolymorphicProps, polymorphicFactory } from '../src'
2+
import { type ComponentWithAs, type HTMLPolymorphicProps, polymorphicFactory } from '../src'
33
import { splitProps } from 'solid-js'
44
import { Dynamic } from 'solid-js/web'
55

@@ -97,5 +97,12 @@ describe('Polymorphic Factory', () => {
9797
// @ts-expect-error Property 'customProp' is missing
9898
render(() => <CustomComponent />)
9999
})
100+
101+
it('should allow arbitrary components for the as prop', () => {
102+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
103+
const Comp = (_props: Record<never, never>) => null
104+
const CustomComp: ComponentWithAs<typeof Comp> = (props) => <poly.div as={Comp} {...props} />
105+
render(() => <CustomComp />)
106+
})
100107
})
101108
})

0 commit comments

Comments
 (0)