Subscribe on changes!

type Inference incorrect of `DefineComponent` with `HTMLAttributes`

avatar
Sep 27th 2021

Version

3.2.19

Reproduction link

Steps to reproduce

const props = {
  propA: Number,
  propB: [String, Number],
  propC: {
    type: String,
    required: true,
  },
}

const Comp = defineComponent({
  props,
  setup() {
    return <div></div>
  },
}) as unknown as DefineComponent<HTMLAttributes & typeof props>

const render = () => {
  const onClick = () => {}
  return <Comp propA={1} onClick={onClick}></Comp>
}

What is expected?

What is actually happening?

image

Type 'number' is not assignable to type 'NumberConstructor'.

avatar
Sep 27th 2021

The cause of this problem is due to this change: #4578

avatar
Sep 27th 2021
const Comp = defineComponent({
  props,
  setup() {
    return <div></div>
  },
}) as unknown as DefineComponent<HTMLAttributes & ExtractPropTypes<typeof props>>

Using 'ExtractPropTypes' to wrap props makes it work, is there a better solution? Then I had a new problem, when I changed 'required' to 'default'

const props = {
  propA: Number,
  propB: [String, Number],
  propC: {
    type: String,
    default: 'true', // required => default
  },
}

const Comp = defineComponent({
  props,
  setup() {
    return <div></div>
  },
}) as unknown as DefineComponent<HTMLAttributes & ExtractPropTypes<typeof props>>

const render = () => {
  const onClick = () => {}
  return <Comp propB={'123'} onClick={onClick}></Comp>
}

image

avatar
Sep 27th 2021

/cc @Amour1688

avatar
Sep 27th 2021

This seems to be the bug of ExtractPropTypes.

And there is a better solution if you want to extends your props

const props = {
  propA: Number,
  propB: [String, Number],
  propC: {
    type: String,
    required: true,
  },
}

const Comp = defineComponent<HTMLAttributes & ExtractPropTypes<typeof props>>({
  setup() {
    return <div></div>
  },
})

// for runtime
Comp.props = props
avatar
Sep 30th 2021

my final solution is as follows:

export const iconProps = {
  iconfont: IxPropTypes.bool.def(false),
  name: IxPropTypes.string,
  rotate: IxPropTypes.oneOfType([Boolean, Number, String]),
}

export type IconProps = IxInnerPropTypes<typeof iconProps> // This is the type used internally
export type IconPublicProps = IxPublicPropTypes<typeof iconProps> // This is the type of exposure to the user
export type IconComponent = DefineComponent<Omit<HTMLAttributes, keyof IconPublicProps> & IconPublicProps>
export type IconInstance = InstanceType<DefineComponent<IconProps>>

'IxInnerPropTypes' and' IxPublicPropTypes' are defined in https://github.com/IDuxFE/idux/blob/main/packages/cdk/utils/src/props.ts#L54

the type of the icon component is defined in https://github.com/IDuxFE/idux/blob/main/packages/components/icon/src/types.ts