Skip to content

Commit

Permalink
feat(types): provide ExtractPublicPropTypes utility type
Browse files Browse the repository at this point in the history
ref #5272
close #8168
  • Loading branch information
yyx990803 committed May 2, 2023
1 parent 918ec8a commit bff63c5
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 3 deletions.
3 changes: 2 additions & 1 deletion packages/compiler-sfc/src/script/resolveType.ts
Expand Up @@ -162,7 +162,8 @@ function innerResolveTypeElements(
case 'TSTypeReference': {
const typeName = getReferenceName(node)
if (
typeName === 'ExtractPropTypes' &&
(typeName === 'ExtractPropTypes' ||
typeName === 'ExtractPublicPropTypes') &&
node.typeParameters &&
scope.imports[typeName]?.source === 'vue'
) {
Expand Down
30 changes: 30 additions & 0 deletions packages/dts-test/extractProps.test-d.ts
@@ -0,0 +1,30 @@
import { ExtractPropTypes, ExtractPublicPropTypes } from 'vue'
import { expectType, Prettify } from './utils'

const propsOptions = {
foo: {
default: 1
},
bar: {
type: String,
required: true
},
baz: Boolean,
qux: Array
} as const

// internal facing props
declare const props: Prettify<ExtractPropTypes<typeof propsOptions>>

expectType<number>(props.foo)
expectType<string>(props.bar)
expectType<boolean>(props.baz)
expectType<unknown[] | undefined>(props.qux)

// external facing props
declare const publicProps: Prettify<ExtractPublicPropTypes<typeof propsOptions>>

expectType<number | undefined>(publicProps.foo)
expectType<string>(publicProps.bar)
expectType<boolean | undefined>(publicProps.baz)
expectType<unknown[] | undefined>(publicProps.qux)
2 changes: 2 additions & 0 deletions packages/dts-test/utils.d.ts
Expand Up @@ -17,3 +17,5 @@ export type IsUnion<T, U extends T = T> = (
: true

export type IsAny<T> = 0 extends 1 & T ? true : false

export type Prettify<T> = { [K in keyof T]: T[K] } & {}
32 changes: 30 additions & 2 deletions packages/runtime-core/src/componentProps.ts
Expand Up @@ -128,14 +128,42 @@ type InferPropType<T> = [T] extends [null]
: V
: T

/**
* Extract prop types from a runtime props options object.
* The extracted types are **internal** - i.e. the resolved props received by
* the component.
* - Boolean props are always present
* - Props with default values are always present
*
* To extract accepted props from the parent, use {@link ExtractPublicPropTypes}.
*/
export type ExtractPropTypes<O> = {
// use `keyof Pick<O, RequiredKeys<O>>` instead of `RequiredKeys<O>` to support IDE features
// use `keyof Pick<O, RequiredKeys<O>>` instead of `RequiredKeys<O>` to
// support IDE features
[K in keyof Pick<O, RequiredKeys<O>>]: InferPropType<O[K]>
} & {
// use `keyof Pick<O, OptionalKeys<O>>` instead of `OptionalKeys<O>` to support IDE features
// use `keyof Pick<O, OptionalKeys<O>>` instead of `OptionalKeys<O>` to
// support IDE features
[K in keyof Pick<O, OptionalKeys<O>>]?: InferPropType<O[K]>
}

type PublicRequiredKeys<T> = {
[K in keyof T]: T[K] extends { required: true } ? K : never
}[keyof T]

type PublicOptionalKeys<T> = Exclude<keyof T, PublicRequiredKeys<T>>

/**
* Extract prop types from a runtime props options object.
* The extracted types are **public** - i.e. the expected props that can be
* passed to component.
*/
export type ExtractPublicPropTypes<O> = {
[K in keyof Pick<O, PublicRequiredKeys<O>>]: InferPropType<O[K]>
} & {
[K in keyof Pick<O, PublicOptionalKeys<O>>]?: InferPropType<O[K]>
}

const enum BooleanFlags {
shouldCast,
shouldCastTrue
Expand Down
1 change: 1 addition & 0 deletions packages/runtime-core/src/index.ts
Expand Up @@ -254,6 +254,7 @@ export type {
ComponentPropsOptions,
ComponentObjectPropsOptions,
ExtractPropTypes,
ExtractPublicPropTypes,
ExtractDefaultPropTypes
} from './componentProps'
export type {
Expand Down

0 comments on commit bff63c5

Please sign in to comment.