Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
30 changes: 25 additions & 5 deletions packages-private/dts-test/defineComponent.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1565,7 +1565,7 @@ export default {
}

describe('slots', () => {
const comp1 = defineComponent({
const Comp1 = defineComponent({
slots: Object as SlotsType<{
default: { foo: string; bar: number }
optional?: { data: string }
Expand Down Expand Up @@ -1613,18 +1613,38 @@ describe('slots', () => {
// @ts-expect-error
slots.optionalUndefinedScope?.('foo')

expectType<typeof slots | undefined>(new comp1().$slots)
expectType<typeof slots | undefined>(new Comp1().$slots)
},
})

const comp2 = defineComponent({
;<Comp1>
{({ bar, foo }) => [
<>
{bar}
{foo}
</>,
]}
</Comp1>
Comment thread
zhiyuanzmj marked this conversation as resolved.
;<Comp1>
{{
default: ({ bar, foo }) => [
<>
{bar}
{foo}
</>,
],
undefinedScope: () => [],
}}
</Comp1>
Comment thread
zhiyuanzmj marked this conversation as resolved.

const Comp2 = defineComponent({
setup(props, { slots }) {
// unknown slots
expectType<Slots>(slots)
expectType<((...args: any[]) => VNode[]) | undefined>(slots.default)
},
})
expectType<Slots | undefined>(new comp2().$slots)
expectType<Slots | undefined>(new Comp2().$slots)
expectType<{}>(new Comp2().$props)
})

// #5885
Expand Down
6 changes: 6 additions & 0 deletions packages-private/dts-test/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
// register global JSX
import 'vue/jsx'

declare module 'vue' {
interface JSXElementChildrenAttribute {
'v-slots': {}
}
}

export function describe(_name: string, _fn: () => void): void
export function test(_name: string, _fn: () => any): void

Expand Down
12 changes: 5 additions & 7 deletions packages/runtime-core/src/apiDefineComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type {
ComponentPropsOptions,
ExtractDefaultPropTypes,
ExtractPropTypes,
ResolveComponentProps,
} from './componentProps'
import type {
EmitsOptions,
Expand Down Expand Up @@ -116,7 +117,7 @@ export type DefineSetupFnComponent<
P extends Record<string, any>,
E extends EmitsOptions = {},
S extends SlotsType = SlotsType,
Props = P & EmitsToProps<E>,
Props = ResolveComponentProps<P, E, S>,
PP = PublicProps,
> = new (
props: Props & PP,
Expand All @@ -136,9 +137,6 @@ export type DefineSetupFnComponent<
S
>

type ToResolvedProps<Props, Emits extends EmitsOptions> = Readonly<Props> &
Readonly<EmitsToProps<Emits>>

// defineComponent is a utility that is primarily used for type inference
// when declaring components. Type inference is provided in the component
// options (provided as the argument). The returned value has artificial types
Expand Down Expand Up @@ -237,7 +235,7 @@ export function defineComponent<
*/
__typeEl?: TypeEl
} & ComponentOptionsBase<
ToResolvedProps<InferredProps, ResolvedEmits>,
ResolveComponentProps<InferredProps, ResolvedEmits, Slots>,
SetupBindings,
Data,
Computed,
Expand All @@ -257,7 +255,7 @@ export function defineComponent<
> &
ThisType<
CreateComponentPublicInstanceWithMixins<
ToResolvedProps<InferredProps, ResolvedEmits>,
ResolveComponentProps<InferredProps, ResolvedEmits, Slots>,
SetupBindings,
Data,
Computed,
Expand Down Expand Up @@ -286,7 +284,7 @@ export function defineComponent<
ResolvedEmits,
RuntimeEmitsKeys,
PublicProps,
ToResolvedProps<InferredProps, ResolvedEmits>,
ResolveComponentProps<InferredProps, ResolvedEmits, Slots>,
ExtractDefaultPropTypes<RuntimePropsOptions>,
Slots,
LocalComponents,
Expand Down
40 changes: 39 additions & 1 deletion packages/runtime-core/src/componentProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ import {
type Data,
setCurrentInstance,
} from './component'
import { isEmitListener } from './componentEmits'
import { type EmitsOptions, isEmitListener } from './componentEmits'
import type { AppContext } from './apiCreateApp'
import { createPropsDefaultThis } from './compat/props'
import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
import { DeprecationTypes } from './compat/compatConfig'
import { shouldSkipAttr } from './compat/attrsFallthrough'
import { createInternalObject } from './internalObject'
import type { EmitsToProps, SlotsType, VNodeChild } from '@vue/runtime-core'
import type { UnwrapSlotsType } from './componentSlots'
Comment thread
zhiyuanzmj marked this conversation as resolved.
Outdated

export type ComponentPropsOptions<P = Data> =
| ComponentObjectPropsOptions<P>
Expand Down Expand Up @@ -190,6 +192,42 @@ type NormalizedProp = PropOptions & {
export type NormalizedProps = Record<string, NormalizedProp>
export type NormalizedPropsOptions = [NormalizedProps, string[]] | []

/**
* Defines which prop name is used for children (slots) type checking.
*
* This is not set by default. To enable it, add the following
* declaration in your vue-jsx project:
*
* ```ts
* declare module 'vue' {
* interface JSXElementChildrenAttribute {
* 'v-slots': {}
* }
* }
* ```
*
* @see {@link https://www.typescriptlang.org/docs/handbook/jsx.html#children-type-checking}
*/
export interface JSXElementChildrenAttribute {}

export type ResolveComponentProps<
Props,
Emits extends EmitsOptions,
RawSlots extends SlotsType | Record<string, any> = Record<string, any>,
Element = VNodeChild,
Slots = RawSlots extends SlotsType ? UnwrapSlotsType<RawSlots> : RawSlots,
> = Readonly<Props> &
Readonly<EmitsToProps<Emits>> &
(string extends keyof Slots
? {}
: keyof JSXElementChildrenAttribute extends infer Key extends string
? {
[K in Key]?:
| ('default' extends keyof Slots ? Slots['default'] | Slots : Slots)
| NoInfer<Element>
}
: {})

export function initProps(
instance: ComponentInternalInstance,
rawProps: Data | null,
Expand Down
2 changes: 2 additions & 0 deletions packages/runtime-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ export type {
ExtractPropTypes,
ExtractPublicPropTypes,
ExtractDefaultPropTypes,
JSXElementChildrenAttribute,
ResolveComponentProps,
} from './componentProps'
export type {
Directive,
Expand Down
8 changes: 7 additions & 1 deletion packages/vue/jsx-runtime/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import type { NativeElements, ReservedProps, VNode } from '@vue/runtime-dom'
import type {
JSXElementChildrenAttribute,
NativeElements,
ReservedProps,
VNode,
} from '@vue/runtime-dom'

/**
* JSX namespace for usage with @jsxImportsSource directive
Expand All @@ -16,6 +21,7 @@ export namespace JSX {
export interface ElementAttributesProperty {
$props: {}
}
export interface ElementChildrenAttribute extends JSXElementChildrenAttribute {}
export interface IntrinsicElements extends NativeElements {
// allow arbitrary elements
// @ts-ignore suppress ts:2374 = Duplicate string index signature.
Expand Down
8 changes: 7 additions & 1 deletion packages/vue/jsx.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
// global JSX namespace registration
// somehow we have to copy=pase the jsx-runtime types here to make TypeScript happy
import type { NativeElements, ReservedProps, VNode } from '@vue/runtime-dom'
import type {
JSXElementChildrenAttribute,
NativeElements,
ReservedProps,
VNode,
} from '@vue/runtime-dom'

declare global {
namespace JSX {
Expand All @@ -12,6 +17,7 @@ declare global {
export interface ElementAttributesProperty {
$props: {}
}
export interface ElementChildrenAttribute extends JSXElementChildrenAttribute {}
export interface IntrinsicElements extends NativeElements {
// allow arbitrary elements
// @ts-ignore suppress ts:2374 = Duplicate string index signature.
Expand Down
Loading