2020-11-25 04:12:59 +08:00
|
|
|
import {
|
|
|
|
type Ref,
|
|
|
|
type Slots,
|
|
|
|
type VNode,
|
2024-01-11 17:57:47 +08:00
|
|
|
defineComponent,
|
2021-06-23 03:02:56 +08:00
|
|
|
defineEmits,
|
2023-11-09 14:52:28 +08:00
|
|
|
defineModel,
|
2024-05-04 04:27:23 +08:00
|
|
|
defineOptions,
|
2020-11-25 04:12:59 +08:00
|
|
|
defineProps,
|
2023-04-03 16:49:16 +08:00
|
|
|
defineSlots,
|
2023-12-26 19:39:47 +08:00
|
|
|
toRefs,
|
2021-07-02 19:51:09 +08:00
|
|
|
useAttrs,
|
2024-01-11 17:57:47 +08:00
|
|
|
useModel,
|
2021-07-02 19:51:09 +08:00
|
|
|
useSlots,
|
2021-06-27 09:35:00 +08:00
|
|
|
withDefaults,
|
2023-02-03 21:41:33 +08:00
|
|
|
} from 'vue'
|
|
|
|
import { describe, expectType } from './utils'
|
2020-11-25 04:12:59 +08:00
|
|
|
|
|
|
|
describe('defineProps w/ type declaration', () => {
|
|
|
|
// type declaration
|
|
|
|
const props = defineProps<{
|
|
|
|
foo: string
|
2023-02-02 10:57:28 +08:00
|
|
|
bool?: boolean
|
|
|
|
boolAndUndefined: boolean | undefined
|
2023-11-09 14:52:28 +08:00
|
|
|
file?: File | File[]
|
2020-11-25 04:12:59 +08:00
|
|
|
}>()
|
|
|
|
// explicitly declared type should be refined
|
|
|
|
expectType<string>(props.foo)
|
|
|
|
// @ts-expect-error
|
|
|
|
props.bar
|
2023-02-02 10:57:28 +08:00
|
|
|
|
|
|
|
expectType<boolean>(props.bool)
|
|
|
|
expectType<boolean>(props.boolAndUndefined)
|
2020-11-25 04:12:59 +08:00
|
|
|
})
|
|
|
|
|
2023-03-26 15:58:04 +08:00
|
|
|
describe('defineProps w/ generics', () => {
|
|
|
|
function test<T extends boolean>() {
|
|
|
|
const props = defineProps<{ foo: T; bar: string; x?: boolean }>()
|
|
|
|
expectType<T>(props.foo)
|
|
|
|
expectType<string>(props.bar)
|
|
|
|
expectType<boolean>(props.x)
|
|
|
|
}
|
|
|
|
test()
|
|
|
|
})
|
|
|
|
|
2024-08-05 10:59:44 +08:00
|
|
|
describe('defineProps w/ type declaration + withDefaults', <T extends
|
|
|
|
string>() => {
|
2021-06-27 09:11:57 +08:00
|
|
|
const res = withDefaults(
|
|
|
|
defineProps<{
|
|
|
|
number?: number
|
|
|
|
arr?: string[]
|
|
|
|
obj?: { x: number }
|
|
|
|
fn?: (e: string) => void
|
2022-05-23 08:28:39 +08:00
|
|
|
genStr?: string
|
2022-11-08 10:59:31 +08:00
|
|
|
x?: string
|
|
|
|
y?: string
|
|
|
|
z?: string
|
2023-02-02 10:57:28 +08:00
|
|
|
bool?: boolean
|
|
|
|
boolAndUndefined: boolean | undefined
|
2024-08-05 10:59:44 +08:00
|
|
|
foo?: T
|
2021-06-27 09:11:57 +08:00
|
|
|
}>(),
|
2021-06-26 07:31:47 +08:00
|
|
|
{
|
2021-06-27 09:11:57 +08:00
|
|
|
number: 123,
|
|
|
|
arr: () => [],
|
2021-06-26 07:31:47 +08:00
|
|
|
obj: () => ({ x: 123 }),
|
2022-05-23 08:28:39 +08:00
|
|
|
fn: () => {},
|
2022-11-08 10:59:31 +08:00
|
|
|
genStr: () => '',
|
|
|
|
y: undefined,
|
|
|
|
z: 'string',
|
2024-08-05 10:59:44 +08:00
|
|
|
foo: '' as any,
|
2021-06-26 07:31:47 +08:00
|
|
|
},
|
|
|
|
)
|
2021-06-27 09:11:57 +08:00
|
|
|
|
|
|
|
res.number + 1
|
|
|
|
res.arr.push('hi')
|
|
|
|
res.obj.x
|
|
|
|
res.fn('hi')
|
2022-11-08 10:59:31 +08:00
|
|
|
res.genStr.slice()
|
2021-06-27 09:11:57 +08:00
|
|
|
// @ts-expect-error
|
|
|
|
res.x.slice()
|
2022-11-08 10:59:31 +08:00
|
|
|
// @ts-expect-error
|
|
|
|
res.y.slice()
|
|
|
|
|
|
|
|
expectType<string | undefined>(res.x)
|
|
|
|
expectType<string | undefined>(res.y)
|
|
|
|
expectType<string>(res.z)
|
2024-08-05 10:59:44 +08:00
|
|
|
expectType<T>(res.foo)
|
2023-02-02 10:57:28 +08:00
|
|
|
|
|
|
|
expectType<boolean>(res.bool)
|
|
|
|
expectType<boolean>(res.boolAndUndefined)
|
2021-06-26 07:31:47 +08:00
|
|
|
})
|
|
|
|
|
2021-11-15 11:09:00 +08:00
|
|
|
describe('defineProps w/ union type declaration + withDefaults', () => {
|
|
|
|
withDefaults(
|
|
|
|
defineProps<{
|
|
|
|
union1?: number | number[] | { x: number }
|
|
|
|
union2?: number | number[] | { x: number }
|
|
|
|
union3?: number | number[] | { x: number }
|
2022-05-23 08:28:39 +08:00
|
|
|
union4?: number | number[] | { x: number }
|
2021-11-15 11:09:00 +08:00
|
|
|
}>(),
|
|
|
|
{
|
|
|
|
union1: 123,
|
|
|
|
union2: () => [123],
|
2022-05-23 08:28:39 +08:00
|
|
|
union3: () => ({ x: 123 }),
|
2023-01-12 20:02:33 +08:00
|
|
|
union4: () => 123,
|
2021-11-15 11:09:00 +08:00
|
|
|
},
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2024-04-15 22:50:34 +08:00
|
|
|
describe('defineProps w/ object union + withDefaults', () => {
|
|
|
|
const props = withDefaults(
|
|
|
|
defineProps<
|
|
|
|
{
|
|
|
|
foo: string
|
|
|
|
} & (
|
|
|
|
| {
|
|
|
|
type: 'hello'
|
|
|
|
bar: string
|
|
|
|
}
|
|
|
|
| {
|
|
|
|
type: 'world'
|
|
|
|
bar: number
|
|
|
|
}
|
|
|
|
)
|
|
|
|
>(),
|
|
|
|
{
|
|
|
|
foo: 'default value!',
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
expectType<
|
|
|
|
| {
|
|
|
|
readonly type: 'hello'
|
|
|
|
readonly bar: string
|
|
|
|
readonly foo: string
|
|
|
|
}
|
|
|
|
| {
|
|
|
|
readonly type: 'world'
|
|
|
|
readonly bar: number
|
|
|
|
readonly foo: string
|
|
|
|
}
|
|
|
|
>(props)
|
|
|
|
})
|
|
|
|
|
2024-08-02 11:45:23 +08:00
|
|
|
describe('defineProps w/ generic discriminate union + withDefaults', () => {
|
|
|
|
interface B {
|
|
|
|
b?: string
|
|
|
|
}
|
|
|
|
interface S<T> extends B {
|
|
|
|
mode: 'single'
|
|
|
|
v: T
|
|
|
|
}
|
|
|
|
interface M<T> extends B {
|
|
|
|
mode: 'multiple'
|
|
|
|
v: T[]
|
|
|
|
}
|
|
|
|
type Props = S<string> | M<string>
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
|
|
b: 'b',
|
|
|
|
})
|
|
|
|
|
|
|
|
if (props.mode === 'single') {
|
|
|
|
expectType<string>(props.v)
|
|
|
|
}
|
|
|
|
if (props.mode === 'multiple') {
|
|
|
|
expectType<string[]>(props.v)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2023-08-11 17:30:04 +08:00
|
|
|
describe('defineProps w/ generic type declaration + withDefaults', <T extends
|
|
|
|
number, TA extends {
|
2023-05-17 09:25:48 +08:00
|
|
|
a: string
|
|
|
|
}, TString extends string>() => {
|
|
|
|
const res = withDefaults(
|
|
|
|
defineProps<{
|
|
|
|
n?: number
|
|
|
|
bool?: boolean
|
2023-11-10 15:20:02 +08:00
|
|
|
s?: string
|
2023-05-17 09:25:48 +08:00
|
|
|
|
|
|
|
generic1?: T[] | { x: T }
|
|
|
|
generic2?: { x: T }
|
|
|
|
generic3?: TString
|
|
|
|
generic4?: TA
|
|
|
|
}>(),
|
|
|
|
{
|
|
|
|
n: 123,
|
|
|
|
|
|
|
|
generic1: () => [123, 33] as T[],
|
2023-08-11 17:30:04 +08:00
|
|
|
generic2: () => ({ x: 123 }) as { x: T },
|
2023-05-17 09:25:48 +08:00
|
|
|
|
|
|
|
generic3: () => 'test' as TString,
|
2023-08-11 17:30:04 +08:00
|
|
|
generic4: () => ({ a: 'test' }) as TA,
|
2023-05-17 09:25:48 +08:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
res.n + 1
|
2023-11-10 15:20:02 +08:00
|
|
|
// @ts-expect-error should be readonly
|
|
|
|
res.n++
|
|
|
|
// @ts-expect-error should be readonly
|
|
|
|
res.s = ''
|
2023-05-17 09:25:48 +08:00
|
|
|
|
|
|
|
expectType<T[] | { x: T }>(res.generic1)
|
|
|
|
expectType<{ x: T }>(res.generic2)
|
|
|
|
expectType<TString>(res.generic3)
|
|
|
|
expectType<TA>(res.generic4)
|
|
|
|
|
|
|
|
expectType<boolean>(res.bool)
|
|
|
|
})
|
|
|
|
|
2023-07-11 18:35:22 +08:00
|
|
|
describe('withDefaults w/ boolean type', () => {
|
|
|
|
const res1 = withDefaults(
|
|
|
|
defineProps<{
|
|
|
|
bool?: boolean
|
|
|
|
}>(),
|
|
|
|
{ bool: false },
|
|
|
|
)
|
|
|
|
expectType<boolean>(res1.bool)
|
|
|
|
|
|
|
|
const res2 = withDefaults(
|
|
|
|
defineProps<{
|
|
|
|
bool?: boolean
|
|
|
|
}>(),
|
|
|
|
{
|
|
|
|
bool: undefined,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
expectType<boolean | undefined>(res2.bool)
|
|
|
|
})
|
|
|
|
|
2024-08-19 16:29:43 +08:00
|
|
|
describe('withDefaults w/ defineProp type is different from the defaults type', () => {
|
|
|
|
const res1 = withDefaults(
|
|
|
|
defineProps<{
|
|
|
|
bool?: boolean
|
|
|
|
}>(),
|
|
|
|
{ bool: false, value: false },
|
|
|
|
)
|
|
|
|
expectType<boolean>(res1.bool)
|
|
|
|
|
|
|
|
// @ts-expect-error
|
|
|
|
res1.value
|
|
|
|
})
|
|
|
|
|
2024-10-11 11:17:15 +08:00
|
|
|
describe('withDefaults w/ defineProp discriminate union type', () => {
|
|
|
|
const props = withDefaults(
|
|
|
|
defineProps<
|
|
|
|
{ type: 'button'; buttonType?: 'submit' } | { type: 'link'; href: string }
|
|
|
|
>(),
|
|
|
|
{
|
|
|
|
type: 'button',
|
|
|
|
},
|
|
|
|
)
|
|
|
|
if (props.type === 'button') {
|
|
|
|
expectType<'submit' | undefined>(props.buttonType)
|
|
|
|
}
|
|
|
|
if (props.type === 'link') {
|
|
|
|
expectType<string>(props.href)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2020-11-25 04:12:59 +08:00
|
|
|
describe('defineProps w/ runtime declaration', () => {
|
|
|
|
// runtime declaration
|
|
|
|
const props = defineProps({
|
|
|
|
foo: String,
|
|
|
|
bar: {
|
|
|
|
type: Number,
|
|
|
|
default: 1,
|
|
|
|
},
|
|
|
|
baz: {
|
|
|
|
type: Array,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
expectType<{
|
|
|
|
foo?: string
|
|
|
|
bar: number
|
|
|
|
baz: unknown[]
|
|
|
|
}>(props)
|
|
|
|
|
|
|
|
props.foo && props.foo + 'bar'
|
|
|
|
props.bar + 1
|
|
|
|
// @ts-expect-error should be readonly
|
|
|
|
props.bar++
|
|
|
|
props.baz.push(1)
|
|
|
|
|
|
|
|
const props2 = defineProps(['foo', 'bar'])
|
|
|
|
props2.foo + props2.bar
|
|
|
|
// @ts-expect-error
|
|
|
|
props2.baz
|
|
|
|
})
|
|
|
|
|
2021-06-23 03:02:56 +08:00
|
|
|
describe('defineEmits w/ type declaration', () => {
|
|
|
|
const emit = defineEmits<(e: 'change') => void>()
|
2020-11-25 04:12:59 +08:00
|
|
|
emit('change')
|
|
|
|
// @ts-expect-error
|
|
|
|
emit()
|
|
|
|
// @ts-expect-error
|
|
|
|
emit('bar')
|
2021-03-30 04:38:07 +08:00
|
|
|
|
|
|
|
type Emits = { (e: 'foo' | 'bar'): void; (e: 'baz', id: number): void }
|
2021-06-23 03:02:56 +08:00
|
|
|
const emit2 = defineEmits<Emits>()
|
2021-03-30 04:38:07 +08:00
|
|
|
|
|
|
|
emit2('foo')
|
|
|
|
emit2('bar')
|
|
|
|
emit2('baz', 123)
|
|
|
|
// @ts-expect-error
|
|
|
|
emit2('baz')
|
2020-11-25 04:12:59 +08:00
|
|
|
})
|
|
|
|
|
2024-11-15 10:46:59 +08:00
|
|
|
describe('defineEmits w/ interface declaration', () => {
|
|
|
|
interface Emits {
|
|
|
|
foo: [value: string]
|
|
|
|
}
|
|
|
|
const emit = defineEmits<Emits>()
|
|
|
|
emit('foo', 'hi')
|
|
|
|
})
|
|
|
|
|
2023-03-30 19:24:32 +08:00
|
|
|
describe('defineEmits w/ alt type declaration', () => {
|
|
|
|
const emit = defineEmits<{
|
|
|
|
foo: [id: string]
|
|
|
|
bar: any[]
|
|
|
|
baz: []
|
|
|
|
}>()
|
|
|
|
|
|
|
|
emit('foo', 'hi')
|
|
|
|
// @ts-expect-error
|
|
|
|
emit('foo')
|
|
|
|
|
|
|
|
emit('bar')
|
|
|
|
emit('bar', 1, 2, 3)
|
|
|
|
|
|
|
|
emit('baz')
|
|
|
|
// @ts-expect-error
|
|
|
|
emit('baz', 1)
|
|
|
|
})
|
|
|
|
|
2021-06-23 03:02:56 +08:00
|
|
|
describe('defineEmits w/ runtime declaration', () => {
|
|
|
|
const emit = defineEmits({
|
2020-11-25 04:12:59 +08:00
|
|
|
foo: () => {},
|
|
|
|
bar: null,
|
|
|
|
})
|
|
|
|
emit('foo')
|
|
|
|
emit('bar', 123)
|
|
|
|
// @ts-expect-error
|
|
|
|
emit('baz')
|
|
|
|
|
2021-06-23 03:02:56 +08:00
|
|
|
const emit2 = defineEmits(['foo', 'bar'])
|
2020-11-25 04:12:59 +08:00
|
|
|
emit2('foo')
|
|
|
|
emit2('bar', 123)
|
|
|
|
// @ts-expect-error
|
|
|
|
emit2('baz')
|
|
|
|
})
|
|
|
|
|
2023-04-03 16:49:16 +08:00
|
|
|
describe('defineSlots', () => {
|
|
|
|
// literal fn syntax (allow for specifying return type)
|
|
|
|
const fnSlots = defineSlots<{
|
|
|
|
default(props: { foo: string; bar: number }): any
|
|
|
|
optional?(props: string): any
|
|
|
|
}>()
|
|
|
|
expectType<(scope: { foo: string; bar: number }) => VNode[]>(fnSlots.default)
|
|
|
|
expectType<undefined | ((scope: string) => VNode[])>(fnSlots.optional)
|
|
|
|
|
|
|
|
const slotsUntype = defineSlots()
|
|
|
|
expectType<Slots>(slotsUntype)
|
|
|
|
})
|
|
|
|
|
2023-12-08 22:54:57 +08:00
|
|
|
describe('defineSlots generic', <T extends Record<string, any>>() => {
|
|
|
|
const props = defineProps<{
|
|
|
|
item: T
|
|
|
|
}>()
|
|
|
|
|
|
|
|
const slots = defineSlots<
|
|
|
|
{
|
|
|
|
[K in keyof T as `slot-${K & string}`]?: (props: { item: T }) => any
|
|
|
|
} & {
|
|
|
|
label?: (props: { item: T }) => any
|
|
|
|
}
|
|
|
|
>()
|
|
|
|
|
|
|
|
for (const key of Object.keys(props.item) as (keyof T & string)[]) {
|
|
|
|
slots[`slot-${String(key)}`]?.({
|
|
|
|
item: props.item,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
slots.label?.({ item: props.item })
|
|
|
|
|
|
|
|
// @ts-expect-error calling wrong slot
|
|
|
|
slots.foo({})
|
|
|
|
})
|
|
|
|
|
2023-04-08 12:13:05 +08:00
|
|
|
describe('defineModel', () => {
|
|
|
|
// overload 1
|
|
|
|
const modelValueRequired = defineModel<boolean>({ required: true })
|
|
|
|
expectType<Ref<boolean>>(modelValueRequired)
|
|
|
|
|
|
|
|
// overload 2
|
|
|
|
const modelValue = defineModel<string>()
|
|
|
|
expectType<Ref<string | undefined>>(modelValue)
|
|
|
|
modelValue.value = 'new value'
|
|
|
|
|
|
|
|
const modelValueDefault = defineModel<boolean>({ default: true })
|
|
|
|
expectType<Ref<boolean>>(modelValueDefault)
|
|
|
|
|
|
|
|
// overload 3
|
|
|
|
const countRequired = defineModel<number>('count', { required: false })
|
|
|
|
expectType<Ref<number | undefined>>(countRequired)
|
|
|
|
|
|
|
|
// overload 4
|
|
|
|
const count = defineModel<number>('count')
|
|
|
|
expectType<Ref<number | undefined>>(count)
|
|
|
|
|
|
|
|
const countDefault = defineModel<number>('count', { default: 1 })
|
|
|
|
expectType<Ref<number>>(countDefault)
|
|
|
|
|
|
|
|
// infer type from default
|
|
|
|
const inferred = defineModel({ default: 123 })
|
|
|
|
expectType<Ref<number | undefined>>(inferred)
|
|
|
|
const inferredRequired = defineModel({ default: 123, required: true })
|
|
|
|
expectType<Ref<number>>(inferredRequired)
|
|
|
|
|
2023-12-26 22:13:04 +08:00
|
|
|
// modifiers
|
|
|
|
const [_, modifiers] = defineModel<string>()
|
|
|
|
expectType<true | undefined>(modifiers.foo)
|
|
|
|
|
|
|
|
// limit supported modifiers
|
|
|
|
const [__, typedModifiers] = defineModel<string, 'trim' | 'capitalize'>()
|
|
|
|
expectType<true | undefined>(typedModifiers.trim)
|
|
|
|
expectType<true | undefined>(typedModifiers.capitalize)
|
|
|
|
// @ts-expect-error
|
|
|
|
typedModifiers.foo
|
|
|
|
|
|
|
|
// transformers with type
|
|
|
|
defineModel<string>({
|
|
|
|
get(val) {
|
|
|
|
return val.toLowerCase()
|
|
|
|
},
|
|
|
|
set(val) {
|
|
|
|
return val.toUpperCase()
|
|
|
|
},
|
|
|
|
})
|
|
|
|
// transformers with runtime type
|
|
|
|
defineModel({
|
|
|
|
type: String,
|
|
|
|
get(val) {
|
|
|
|
return val.toLowerCase()
|
|
|
|
},
|
|
|
|
set(val) {
|
|
|
|
return val.toUpperCase()
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2023-04-08 12:13:05 +08:00
|
|
|
// @ts-expect-error type / default mismatch
|
|
|
|
defineModel<string>({ default: 123 })
|
|
|
|
// @ts-expect-error unknown props option
|
|
|
|
defineModel({ foo: 123 })
|
2024-09-03 17:47:50 +08:00
|
|
|
|
|
|
|
// unrelated getter and setter types
|
|
|
|
{
|
|
|
|
const modelVal = defineModel({
|
|
|
|
get(_: string[]): string {
|
|
|
|
return ''
|
|
|
|
},
|
|
|
|
set(_: number) {
|
|
|
|
return 1
|
|
|
|
},
|
|
|
|
})
|
|
|
|
expectType<string | undefined>(modelVal.value)
|
|
|
|
modelVal.value = 1
|
|
|
|
modelVal.value = undefined
|
|
|
|
// @ts-expect-error
|
|
|
|
modelVal.value = 'foo'
|
|
|
|
|
|
|
|
const [modelVal2] = modelVal
|
|
|
|
expectType<string | undefined>(modelVal2.value)
|
|
|
|
modelVal2.value = 1
|
|
|
|
modelVal2.value = undefined
|
|
|
|
// @ts-expect-error
|
|
|
|
modelVal.value = 'foo'
|
|
|
|
|
|
|
|
const count = defineModel('count', {
|
|
|
|
get(_: string[]): string {
|
|
|
|
return ''
|
|
|
|
},
|
|
|
|
set(_: number) {
|
|
|
|
return ''
|
|
|
|
},
|
|
|
|
})
|
|
|
|
expectType<string | undefined>(count.value)
|
|
|
|
count.value = 1
|
|
|
|
count.value = undefined
|
|
|
|
// @ts-expect-error
|
|
|
|
count.value = 'foo'
|
|
|
|
|
|
|
|
const [count2] = count
|
|
|
|
expectType<string | undefined>(count2.value)
|
|
|
|
count2.value = 1
|
|
|
|
count2.value = undefined
|
|
|
|
// @ts-expect-error
|
|
|
|
count2.value = 'foo'
|
|
|
|
}
|
2023-04-08 12:13:05 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
describe('useModel', () => {
|
|
|
|
defineComponent({
|
|
|
|
props: ['foo'],
|
|
|
|
setup(props) {
|
|
|
|
const r = useModel(props, 'foo')
|
|
|
|
expectType<Ref<any>>(r)
|
|
|
|
|
|
|
|
// @ts-expect-error
|
|
|
|
useModel(props, 'bar')
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
defineComponent({
|
|
|
|
props: {
|
|
|
|
foo: String,
|
|
|
|
bar: { type: Number, required: true },
|
|
|
|
baz: { type: Boolean },
|
|
|
|
},
|
|
|
|
setup(props) {
|
|
|
|
expectType<Ref<string | undefined>>(useModel(props, 'foo'))
|
|
|
|
expectType<Ref<number>>(useModel(props, 'bar'))
|
|
|
|
expectType<Ref<boolean>>(useModel(props, 'baz'))
|
|
|
|
},
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-07-02 19:51:09 +08:00
|
|
|
describe('useAttrs', () => {
|
|
|
|
const attrs = useAttrs()
|
|
|
|
expectType<Record<string, unknown>>(attrs)
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('useSlots', () => {
|
|
|
|
const slots = useSlots()
|
|
|
|
expectType<Slots>(slots)
|
|
|
|
})
|
2023-11-09 14:52:28 +08:00
|
|
|
|
2023-12-08 22:54:57 +08:00
|
|
|
describe('defineSlots generic', <T extends Record<string, any>>() => {
|
|
|
|
const props = defineProps<{
|
|
|
|
item: T
|
|
|
|
}>()
|
|
|
|
|
|
|
|
const slots = defineSlots<
|
|
|
|
{
|
|
|
|
[K in keyof T as `slot-${K & string}`]?: (props: { item: T }) => any
|
|
|
|
} & {
|
|
|
|
label?: (props: { item: T }) => any
|
|
|
|
}
|
|
|
|
>()
|
|
|
|
|
|
|
|
// @ts-expect-error slots should be readonly
|
|
|
|
slots.label = () => {}
|
|
|
|
|
|
|
|
// @ts-expect-error non existing slot
|
|
|
|
slots['foo-asdas']?.({
|
|
|
|
item: props.item,
|
|
|
|
})
|
|
|
|
for (const key in props.item) {
|
|
|
|
slots[`slot-${String(key)}`]?.({
|
|
|
|
item: props.item,
|
|
|
|
})
|
|
|
|
slots[`slot-${String(key as keyof T)}`]?.({
|
|
|
|
item: props.item,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const key of Object.keys(props.item) as (keyof T)[]) {
|
|
|
|
slots[`slot-${String(key)}`]?.({
|
|
|
|
item: props.item,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
slots.label?.({ item: props.item })
|
|
|
|
|
|
|
|
// @ts-expect-error calling wrong slot
|
|
|
|
slots.foo({})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('defineSlots generic strict', <T extends {
|
|
|
|
foo: 'foo'
|
|
|
|
bar: 'bar'
|
|
|
|
}>() => {
|
|
|
|
const props = defineProps<{
|
|
|
|
item: T
|
|
|
|
}>()
|
|
|
|
|
|
|
|
const slots = defineSlots<
|
|
|
|
{
|
|
|
|
[K in keyof T as `slot-${K & string}`]?: (props: { item: T }) => any
|
|
|
|
} & {
|
|
|
|
label?: (props: { item: T }) => any
|
|
|
|
}
|
|
|
|
>()
|
|
|
|
|
|
|
|
// slot-bar/foo should be automatically inferred
|
|
|
|
slots['slot-bar']?.({ item: props.item })
|
|
|
|
slots['slot-foo']?.({ item: props.item })
|
|
|
|
|
|
|
|
slots.label?.({ item: props.item })
|
|
|
|
|
|
|
|
// @ts-expect-error not part of the extends
|
|
|
|
slots['slot-RANDOM']?.({ item: props.item })
|
|
|
|
|
|
|
|
// @ts-expect-error slots should be readonly
|
|
|
|
slots.label = () => {}
|
|
|
|
|
|
|
|
// @ts-expect-error calling wrong slot
|
|
|
|
slots.foo({})
|
|
|
|
})
|
|
|
|
|
2023-11-09 14:52:28 +08:00
|
|
|
// #6420
|
|
|
|
describe('toRefs w/ type declaration', () => {
|
|
|
|
const props = defineProps<{
|
|
|
|
file?: File | File[]
|
|
|
|
}>()
|
|
|
|
expectType<Ref<File | File[] | undefined>>(toRefs(props).file)
|
|
|
|
})
|
2024-05-04 04:27:23 +08:00
|
|
|
|
|
|
|
describe('defineOptions', () => {
|
|
|
|
defineOptions({
|
|
|
|
name: 'MyComponent',
|
|
|
|
inheritAttrs: true,
|
|
|
|
})
|
|
|
|
|
|
|
|
defineOptions({
|
|
|
|
// @ts-expect-error props should be defined via defineProps()
|
|
|
|
props: ['props'],
|
|
|
|
// @ts-expect-error emits should be defined via defineEmits()
|
|
|
|
emits: ['emits'],
|
|
|
|
// @ts-expect-error slots should be defined via defineSlots()
|
|
|
|
slots: { default: 'default' },
|
|
|
|
// @ts-expect-error expose should be defined via defineExpose()
|
|
|
|
expose: ['expose'],
|
|
|
|
})
|
|
|
|
})
|