Skip to content

Commit b8cc94b

Browse files
author
danil.nemov
committed
fix: make inferring from runtime props possible in case props types aren't specified
1 parent 7f374a3 commit b8cc94b

File tree

2 files changed

+74
-41
lines changed

2 files changed

+74
-41
lines changed

packages-private/dts-test/defineComponent.test-d.tsx

Lines changed: 58 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
type Component,
33
type ComponentOptions,
44
type ComponentPublicInstance,
5+
type DefineSetupFnComponent,
56
type PropType,
67
type SetupContext,
78
type Slots,
@@ -1411,6 +1412,14 @@ describe('function syntax w/ runtime props', () => {
14111412
},
14121413
)
14131414

1415+
expectType<JSX.Element>(<Comp1 msg="1" />)
1416+
// @ts-expect-error msg type is incorrect
1417+
expectType<JSX.Element>(<Comp1 msg={1} />)
1418+
// @ts-expect-error msg is missing
1419+
expectType<JSX.Element>(<Comp1 />)
1420+
// @ts-expect-error bar doesn't exist
1421+
expectType<JSX.Element>(<Comp1 msg="1" bar="2" />)
1422+
14141423
// @ts-expect-error bar isn't specified in props definition
14151424
defineComponent(
14161425
(_props: { msg: string }) => {
@@ -1430,13 +1439,15 @@ describe('function syntax w/ runtime props', () => {
14301439
},
14311440
)
14321441

1433-
expectType<JSX.Element>(<Comp1 msg="1" />)
1434-
// @ts-expect-error msg type is incorrect
1435-
expectType<JSX.Element>(<Comp1 msg={1} />)
1436-
// @ts-expect-error msg is missing
1437-
expectType<JSX.Element>(<Comp1 />)
1438-
// @ts-expect-error bar doesn't exist
1439-
expectType<JSX.Element>(<Comp1 msg="1" bar="2" />)
1442+
// @ts-expect-error string prop names don't match
1443+
defineComponent(
1444+
(_props: { msg: string }) => {
1445+
return () => {}
1446+
},
1447+
{
1448+
props: ['bar'],
1449+
},
1450+
)
14401451

14411452
const Comp2 = defineComponent(
14421453
<T extends string>(_props: { msg: T }) => {
@@ -1447,8 +1458,16 @@ describe('function syntax w/ runtime props', () => {
14471458
},
14481459
)
14491460

1450-
// @ts-expect-error bar isn't specified in props definition
1451-
defineComponent(
1461+
expectType<JSX.Element>(<Comp2 msg="1" />)
1462+
expectType<JSX.Element>(<Comp2<string> msg="1" />)
1463+
// @ts-expect-error msg type is incorrect
1464+
expectType<JSX.Element>(<Comp2 msg={1} />)
1465+
// @ts-expect-error msg is missing
1466+
expectType<JSX.Element>(<Comp2 />)
1467+
// @ts-expect-error bar doesn't exist
1468+
expectType<JSX.Element>(<Comp2 msg="1" bar="2" />)
1469+
1470+
const Comp3 = defineComponent(
14521471
<T extends string>(_props: { msg: T }) => {
14531472
return () => {}
14541473
},
@@ -1457,6 +1476,12 @@ describe('function syntax w/ runtime props', () => {
14571476
},
14581477
)
14591478

1479+
// This is not the preferred behavior because it's better to see a typescript error,
1480+
// but this is a compromise to resolve a relatively worse problem -
1481+
// not inferring props types from runtime props when the types are not explicitly set.
1482+
// See #13119#discussion_r2137831991
1483+
expectType<DefineSetupFnComponent<{ msg: any; bar: any }>>(Comp3)
1484+
14601485
defineComponent(
14611486
<T extends string>(_props: { msg: T; bar: T }) => {
14621487
return () => {}
@@ -1466,17 +1491,9 @@ describe('function syntax w/ runtime props', () => {
14661491
},
14671492
)
14681493

1469-
expectType<JSX.Element>(<Comp2 msg="1" />)
1470-
expectType<JSX.Element>(<Comp2<string> msg="1" />)
1471-
// @ts-expect-error msg type is incorrect
1472-
expectType<JSX.Element>(<Comp2 msg={1} />)
1473-
// @ts-expect-error msg is missing
1474-
expectType<JSX.Element>(<Comp2 />)
1475-
// @ts-expect-error bar doesn't exist
1476-
expectType<JSX.Element>(<Comp2 msg="1" bar="2" />)
1477-
14781494
// Note: generics aren't supported with object runtime props
1479-
const Comp3 = defineComponent(
1495+
// so the props will infer the runtime props' types
1496+
const Comp4 = defineComponent(
14801497
<T extends string>(_props: { msg: T }) => {
14811498
return () => {}
14821499
},
@@ -1487,6 +1504,17 @@ describe('function syntax w/ runtime props', () => {
14871504
},
14881505
)
14891506

1507+
expectType<DefineSetupFnComponent<{ msg: string }>>(Comp4)
1508+
expectType<JSX.Element>(<Comp4 msg="1" />)
1509+
// @ts-expect-error generics aren't supported with object runtime props
1510+
expectType<JSX.Element>(<Comp4<string> msg="1" />)
1511+
// @ts-expect-error msg type is incorrect
1512+
expectType<JSX.Element>(<Comp4 msg={1} />)
1513+
// @ts-expect-error msg is missing
1514+
expectType<JSX.Element>(<Comp4 />)
1515+
// @ts-expect-error bar doesn't exist
1516+
expectType<JSX.Element>(<Comp4 msg="1" bar="2" />)
1517+
14901518
defineComponent(
14911519
// @ts-expect-error bar isn't specified in props definition
14921520
<T extends string>(_props: { msg: T }) => {
@@ -1500,46 +1528,35 @@ describe('function syntax w/ runtime props', () => {
15001528
)
15011529

15021530
defineComponent(
1503-
// @ts-expect-error generics aren't supported with object runtime props
1504-
<T extends string>(_props: { msg: T; bar: T }) => {
1531+
(_props: { msg: string }) => {
15051532
return () => {}
15061533
},
15071534
{
15081535
props: {
1509-
msg: String,
1536+
// @ts-expect-error prop type mismatch
1537+
msg: Number,
15101538
},
15111539
},
15121540
)
15131541

1514-
expectType<JSX.Element>(<Comp3 msg="1" />)
1515-
// @ts-expect-error generics aren't supported with object runtime props
1516-
expectType<JSX.Element>(<Comp3<string> msg="1" />)
1517-
// @ts-expect-error msg type is incorrect
1518-
expectType<JSX.Element>(<Comp3 msg={1} />)
1519-
// @ts-expect-error msg is missing
1520-
expectType<JSX.Element>(<Comp3 />)
1521-
// @ts-expect-error bar doesn't exist
1522-
expectType<JSX.Element>(<Comp3 msg="1" bar="2" />)
1523-
1524-
// @ts-expect-error string prop names don't match
1525-
defineComponent(
1526-
(_props: { msg: string }) => {
1542+
const Comp5 = defineComponent(
1543+
_props => {
15271544
return () => {}
15281545
},
15291546
{
1530-
props: ['bar'],
1547+
props: ['foo'],
15311548
},
15321549
)
15331550

1551+
expectType<DefineSetupFnComponent<{ foo: any }>>(Comp5)
1552+
15341553
defineComponent(
1535-
(_props: { msg: string }) => {
1554+
// @ts-expect-error the props type is required when a generic type is present
1555+
<T,>(_props) => {
15361556
return () => {}
15371557
},
15381558
{
1539-
props: {
1540-
// @ts-expect-error prop type mismatch
1541-
msg: Number,
1542-
},
1559+
props: [],
15431560
},
15441561
)
15451562
})

packages/runtime-core/src/apiDefineComponent.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,22 @@ type ToResolvedProps<Props, Emits extends EmitsOptions> = Readonly<Props> &
146146

147147
// overload 1: direct setup function
148148
// (uses user defined props interface)
149+
export function defineComponent<
150+
Props extends Record<string, any>,
151+
E extends EmitsOptions = {},
152+
EE extends string = string,
153+
S extends SlotsType = {},
154+
>(
155+
setup: (
156+
props: Props,
157+
ctx: SetupContext<E, S>,
158+
) => RenderFunction | Promise<RenderFunction>,
159+
options?: Pick<ComponentOptions, 'name' | 'inheritAttrs'> & {
160+
props?: (keyof Props)[]
161+
emits?: E | EE[]
162+
slots?: S
163+
},
164+
): DefineSetupFnComponent<Props, E, S>
149165
export function defineComponent<
150166
Props extends Record<string, any>,
151167
E extends EmitsOptions = {},

0 commit comments

Comments
 (0)