Skip to content

Commit

Permalink
fix(types): declared prop keys should always exist in props argument (
Browse files Browse the repository at this point in the history
  • Loading branch information
Justineo committed May 12, 2021
1 parent f01aadf commit 9b160b9
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 5 deletions.
12 changes: 8 additions & 4 deletions packages/runtime-core/src/componentOptions.ts
Expand Up @@ -65,7 +65,7 @@ import {
import { warn } from './warning'
import { VNodeChild } from './vnode'
import { callWithAsyncErrorHandling } from './errorHandling'
import { UnionToIntersection } from './helpers/typeUtils'
import { LooseRequired, UnionToIntersection } from './helpers/typeUtils'
import { deepMergeData } from './compat/data'
import { DeprecationTypes } from './compat/compatConfig'
import {
Expand Down Expand Up @@ -130,9 +130,13 @@ export interface ComponentOptionsBase<
ComponentCustomOptions {
setup?: (
this: void,
props: Props &
UnionToIntersection<ExtractOptionProp<Mixin>> &
UnionToIntersection<ExtractOptionProp<Extends>>,
props: Readonly<
LooseRequired<
Props &
UnionToIntersection<ExtractOptionProp<Mixin>> &
UnionToIntersection<ExtractOptionProp<Extends>>
>
>,
ctx: SetupContext<E>
) => Promise<RawBindings> | RawBindings | RenderFunction | void
name?: string
Expand Down
3 changes: 3 additions & 0 deletions packages/runtime-core/src/helpers/typeUtils.ts
Expand Up @@ -3,3 +3,6 @@ export type UnionToIntersection<U> = (U extends any
: never) extends ((k: infer I) => void)
? I
: never

// make keys required but keep undefined values
export type LooseRequired<T> = { [P in string & keyof T]: T[P] }
44 changes: 43 additions & 1 deletion test-dts/component.test-d.ts
Expand Up @@ -9,7 +9,8 @@ import {
expectType,
ShallowUnwrapRef,
FunctionalComponent,
ComponentPublicInstance
ComponentPublicInstance,
toRefs
} from './index'

declare function extractComponentOptions<Props, RawBindings>(
Expand Down Expand Up @@ -42,6 +43,27 @@ describe('object props', () => {
object?: object
}

interface ExpectedRefs {
a: Ref<number | undefined>
b: Ref<string>
e: Ref<Function | undefined>
bb: Ref<string>
bbb: Ref<string>
cc: Ref<string[] | undefined>
dd: Ref<{ n: 1 }>
ee: Ref<(() => string) | undefined>
ff: Ref<((a: number, b: string) => { a: boolean }) | undefined>
ccc: Ref<string[] | undefined>
ddd: Ref<string[]>
eee: Ref<() => { a: string }>
fff: Ref<(a: number, b: string) => { a: boolean }>
hhh: Ref<boolean>
ggg: Ref<'foo' | 'bar'>
ffff: Ref<(a: number, b: string) => { a: boolean }>
validated: Ref<string | undefined>
object: Ref<object | undefined>
}

describe('defineComponent', () => {
const MyComponent = defineComponent({
props: {
Expand Down Expand Up @@ -111,6 +133,26 @@ describe('object props', () => {
object: Object as PropType<object>
},
setup(props) {
const refs = toRefs(props)
expectType<ExpectedRefs['a']>(refs.a)
expectType<ExpectedRefs['b']>(refs.b)
expectType<ExpectedRefs['e']>(refs.e)
expectType<ExpectedRefs['bb']>(refs.bb)
expectType<ExpectedRefs['bbb']>(refs.bbb)
expectType<ExpectedRefs['cc']>(refs.cc)
expectType<ExpectedRefs['dd']>(refs.dd)
expectType<ExpectedRefs['ee']>(refs.ee)
expectType<ExpectedRefs['ff']>(refs.ff)
expectType<ExpectedRefs['ccc']>(refs.ccc)
expectType<ExpectedRefs['ddd']>(refs.ddd)
expectType<ExpectedRefs['eee']>(refs.eee)
expectType<ExpectedRefs['fff']>(refs.fff)
expectType<ExpectedRefs['hhh']>(refs.hhh)
expectType<ExpectedRefs['ggg']>(refs.ggg)
expectType<ExpectedRefs['ffff']>(refs.ffff)
expectType<ExpectedRefs['validated']>(refs.validated)
expectType<ExpectedRefs['object']>(refs.object)

return {
setupA: 1,
setupB: ref(1),
Expand Down

0 comments on commit 9b160b9

Please sign in to comment.