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: add defineSlots macro and slots option #7982

Merged
merged 14 commits into from
Apr 3, 2023
Prev Previous commit
Next Next commit
refactor: style
sxzz committed Mar 31, 2023

Verified

This commit was signed with the committer’s verified signature.
sxzz Kevin Deng 三咲智子
commit f908ae22838c8a284e99db3922d2f4d878926933
15 changes: 6 additions & 9 deletions packages/dts-test/defineComponent.test-d.tsx
Original file line number Diff line number Diff line change
@@ -1411,20 +1411,17 @@ export default {
describe('slots', () => {
defineComponent({
slots: Object as SlotsType<{
default: [foo: string, bar: number]
item: [number]
default: { foo: string; bar: number }
item: { data: number }
}>,
setup(props, { slots }) {
expectType<undefined | ((foo: string, bar: number) => any)>(slots.default)
expectType<undefined | ((scope: number) => any)>(slots.item)
expectType<undefined | ((scope: { foo: string; bar: number }) => any)>(
slots.default
)
expectType<undefined | ((scope: { data: number }) => any)>(slots.item)
}
})

defineComponent({
// @ts-expect-error `default` should be an array
slots: Object as SlotsType<{ default: string }>
})

defineComponent({
setup(props, { slots }) {
// unknown slots
6 changes: 4 additions & 2 deletions packages/dts-test/functionalComponent.test-d.tsx
Original file line number Diff line number Diff line change
@@ -69,11 +69,13 @@ const Qux: FunctionalComponent<{}, ['foo', 'bar']> = (props, { emit }) => {

expectType<Component>(Qux)

const Quux: FunctionalComponent<{}, {}, { default: [foo: number] }> = (
const Quux: FunctionalComponent<{}, {}, { default: { foo: number } }> = (
props,
{ emit, slots }
) => {
expectType<{ default: undefined | ((foo: number) => VNode[]) }>(slots)
expectType<{ default: undefined | ((scope: { foo: number }) => VNode[]) }>(
slots
)
}
expectType<Component>(Quux)
;<Quux />
7 changes: 2 additions & 5 deletions packages/dts-test/setupHelpers.test-d.ts
Original file line number Diff line number Diff line change
@@ -183,15 +183,12 @@ describe('defineEmits w/ runtime declaration', () => {

describe('defineSlots', () => {
const slots = defineSlots<{
default: [foo: string, bar: number]
default: { foo: string; bar: number }
}>()
expectType<(foo: string, bar: number) => VNode[]>(slots.default)
expectType<(scope: { foo: string; bar: number }) => VNode[]>(slots.default)

const slotsUntype = defineSlots()
expectType<Slots>(slotsUntype)

// @ts-expect-error `default` should be an array
defineSlots<{ default: string }>()
})

describe('useAttrs', () => {
4 changes: 2 additions & 2 deletions packages/runtime-core/src/apiSetupHelpers.ts
Original file line number Diff line number Diff line change
@@ -190,10 +190,10 @@ export function defineOptions<
}

export function defineSlots<
T extends Record<string, any[]> = Record<string, any[]>
T extends Record<string, any> = Record<string, any>
>(): // @ts-expect-error
Readonly<{
[K in keyof T]: Slot<T[K]>
[K in keyof T]: Slot<[T[K]]>
}> {
if (__DEV__) {
warnRuntimeUsage(`defineSlots`)
2 changes: 1 addition & 1 deletion packages/runtime-core/src/component.ts
Original file line number Diff line number Diff line change
@@ -125,7 +125,7 @@ export interface ComponentInternalOptions {
export interface FunctionalComponent<
P = {},
E extends EmitsOptions = {},
S extends Record<string, any[]> = Record<string, any[]>
S extends Record<string, any> = Record<string, any>
> extends ComponentInternalOptions {
// use of any here is intentional so it can be a valid JSX Element constructor
(props: P, ctx: Omit<SetupContext<E, SlotsType<S>>, 'expose'>): any
13 changes: 7 additions & 6 deletions packages/runtime-core/src/componentSlots.ts
Original file line number Diff line number Diff line change
@@ -23,7 +23,9 @@ import { isHmrUpdating } from './hmr'
import { DeprecationTypes, isCompatEnabled } from './compat/compatConfig'
import { toRaw } from '@vue/reactivity'

export type Slot<T extends any[] = any[]> = (...args: T) => VNode[]
export type Slot<T extends any[] = any[]> = (
...args: T extends [any] ? any[] : T
) => VNode[]

export type InternalSlots = {
[name: string]: Slot | undefined
@@ -32,17 +34,16 @@ export type InternalSlots = {
export type Slots = Readonly<InternalSlots>

declare const SlotSymbol: unique symbol
export type SlotsType<T extends Record<string, any[]> = Record<string, any[]>> =
{
[SlotSymbol]?: T
}
export type SlotsType<T extends Record<string, any> = Record<string, any>> = {
[SlotSymbol]?: T
}

export type TypedSlots<S extends SlotsType> = [keyof S] extends [never]
? Slots
: Readonly<
Prettify<{
[K in keyof NonNullable<S[typeof SlotSymbol]>]:
| Slot<NonNullable<S[typeof SlotSymbol]>[K]>
| Slot<[NonNullable<S[typeof SlotSymbol]>[K]]>
| undefined
}>
>
2 changes: 1 addition & 1 deletion packages/runtime-core/src/h.ts
Original file line number Diff line number Diff line change
@@ -123,7 +123,7 @@ export function h(
export function h<
P,
E extends EmitsOptions = {},
S extends Record<string, any[]> = {}
S extends Record<string, any> = {}
>(
type: FunctionalComponent<P, E, S>,
props?: (RawProps & P) | ({} extends P ? null : never),