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

fix(propfunctionprops): prevent 'undefined', 'null', 'never' conversion to PropFnInterface #5363

Merged
merged 5 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion packages/docs/src/routes/api/qwik/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -1624,7 +1624,7 @@
}
],
"kind": "TypeAlias",
"content": "```typescript\nexport type PropFunctionProps<PROPS extends {}> = {\n [K in keyof PROPS]: NonNullable<PROPS[K]> extends (...args: infer ARGS) => infer RET ? PropFnInterface<ARGS, Awaited<RET>> : PROPS[K];\n};\n```\n**References:** [PropFnInterface](#propfninterface)",
"content": "```typescript\nexport type PropFunctionProps<PROPS extends {}> = {\n [K in keyof PROPS]: PROPS[K] extends undefined ? PROPS[K] : PROPS[K] extends ((...args: infer ARGS) => infer RET) | undefined ? PropFnInterface<ARGS, Awaited<RET>> : PROPS[K];\n};\n```\n**References:** [PropFnInterface](#propfninterface)",
"editUrl": "https://github.com/BuilderIO/qwik/tree/main/packages/qwik/src/core/component/component.public.ts",
"mdFile": "qwik.propfunctionprops.md"
},
Expand Down
6 changes: 3 additions & 3 deletions packages/docs/src/routes/api/qwik/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2123,9 +2123,9 @@ export type PropFunction<T extends Function = (...args: any[]) => any> =

```typescript
export type PropFunctionProps<PROPS extends {}> = {
[K in keyof PROPS]: NonNullable<PROPS[K]> extends (
...args: infer ARGS
) => infer RET
[K in keyof PROPS]: PROPS[K] extends undefined
? PROPS[K]
: PROPS[K] extends ((...args: infer ARGS) => infer RET) | undefined
? PropFnInterface<ARGS, Awaited<RET>>
: PROPS[K];
};
Expand Down
2 changes: 1 addition & 1 deletion packages/qwik/src/core/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1401,7 +1401,7 @@ export type PropFunction<T extends Function = (...args: any[]) => any> = T exten

// @public (undocumented)
export type PropFunctionProps<PROPS extends {}> = {
[K in keyof PROPS]: NonNullable<PROPS[K]> extends (...args: infer ARGS) => infer RET ? PropFnInterface<ARGS, Awaited<RET>> : PROPS[K];
[K in keyof PROPS]: PROPS[K] extends undefined ? PROPS[K] : PROPS[K] extends ((...args: infer ARGS) => infer RET) | undefined ? PropFnInterface<ARGS, Awaited<RET>> : PROPS[K];
};

// @public
Expand Down
4 changes: 3 additions & 1 deletion packages/qwik/src/core/component/component.public.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,9 @@ export const isQwikComponent = (component: any): component is Component<any> =>

/** @public */
export type PropFunctionProps<PROPS extends {}> = {
[K in keyof PROPS]: NonNullable<PROPS[K]> extends (...args: infer ARGS) => infer RET
[K in keyof PROPS]: PROPS[K] extends undefined
? PROPS[K]
: PROPS[K] extends ((...args: infer ARGS) => infer RET) | undefined
? PropFnInterface<ARGS, Awaited<RET>>
: PROPS[K];
};
Expand Down
57 changes: 56 additions & 1 deletion packages/qwik/src/core/component/component.unit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { createDOM } from '../../testing/library';
import { expectDOM } from '../../testing/expect-dom';
import { inlinedQrl } from '../qrl/qrl';
import { useStylesQrl } from '../use/use-styles';
import { type PropsOf, component$ } from './component.public';
import { type PropsOf, component$, type PropFunctionProps } from './component.public';
import { useStore } from '../use/use-store.public';
import { useLexicalScope } from '../use/use-lexical-scope.public';
import { describe, test } from 'vitest';
import type { InputHTMLAttributes } from '../render/jsx/types/jsx-generated';
import type { QwikIntrinsicElements } from '../render/jsx/types/jsx-qwik-elements';

describe('q-component', () => {
/**
Expand Down Expand Up @@ -113,6 +115,59 @@ describe('q-component', () => {
`
);
});

test('types work as expected', () => {
const Input1 = component$<InputHTMLAttributes<HTMLInputElement>>((props) => {
return <input {...props} />;
});

const Input2 = component$((props: PropFunctionProps<InputHTMLAttributes<HTMLInputElement>>) => {
return <input {...props} />;
});

const Input3 = component$((props: Partial<InputHTMLAttributes<HTMLInputElement>>) => {
return <input {...props} />;
});

const Input4 = component$(
(props: Partial<PropFunctionProps<InputHTMLAttributes<HTMLInputElement>>>) => {
return <input {...props} />;
}
);

type Input5Props = {
type: 'text' | 'number';
} & Partial<InputHTMLAttributes<HTMLInputElement>>;

const Input5 = component$<Input5Props>(({ type, ...props }) => {
return <input type={type} {...props} />;
});

type Input6Props = {
type: 'text' | 'number';
} & QwikIntrinsicElements['input'];

const Input6 = component$<Input6Props>(({ type, ...props }) => {
return (
<div>
<input type={type} {...props} />
</div>
);
});

component$(() => {
return (
<>
<Input1 value="1" />
<Input2 value="2" />
<Input3 value="3" />
<Input4 value="4" />
<Input5 value="5" type="text" />
<Input6 value="6" type="number" />
</>
);
});
});
});

/////////////////////////////////////////////////////////////////////////////
Expand Down
Loading