2021-06-28

Why does regular function break type inference?

I have a defineComponent() function that takes an object as an argument. That object can contain a props property, and a setup() property that receives a props argument, whose type is inferred from the props property declared earlier in the object.

Example:

defineComponent({
  props: {
    size: {
      type: String,
      default: 'lg',
      validator: (value: string) => true,
    }
  },
  setup(props) {
    console.log(props.size.charAt(0))
  }
})

Oddly, if props.size.validator is declared as a regular function (validator: function(value: string) { return true }) instead of an arrow function, the inferred type for the props argument is completely wrong. For the above example. it should be:

{
  size: string
}

But it's this:

string[] | {
    [x: string]: Prop<unknown, unknown> | null;
}

The regular function is essentially the same as the arrow function in the working code, so I wasn't expecting it to break the type inference.

Why does a regular function break the type inference for setup()'s props argument?


mylib.d.ts:

declare interface PropOptions<T = any, D = T> {
    type?: PropType<T>;
    required?: boolean;
    default?: D | DefaultFactory<D>;
    validator?(value: unknown): boolean;
}
declare type DefaultFactory<T> = (props: Data) => T;
declare type Data = Record<string, unknown>;
export declare type PropType<T> = PropConstructor<T> | PropConstructor<T>[];
declare type PropConstructor<T = any> = { new (...args: any[]): T & {} };
export declare type Prop<T, D = T> = PropOptions<T, D> | PropType<T>;
export declare type ComponentPropsOptions<P = Data> = ComponentObjectPropsOptions<P> | string[];
export declare type ComponentObjectPropsOptions<P = Data> = { [K in keyof P]: Prop<P[K]> | null };

declare type InferPropType<T> =
  [T] extends [null] ? any 
: [T] extends [{ type: null | true }] ? any
: [T] extends [ObjectConstructor | { type: ObjectConstructor }] ? Record<string, any>
: [T] extends [BooleanConstructor | { type: BooleanConstructor }] ? boolean
: [T] extends [DateConstructor | { type: DateConstructor }] ? Date
: [T] extends [Prop<infer V, infer D>] ? (unknown extends V ? D : V)
: T;

export declare type ExtractPropTypes<O> =
  O extends object
  ? { [K in keyof O]: InferPropType<O[K]> }
  : { [K in string]: any };

export declare interface ComponentOptionsBase<Props> {
  setup?: (this: void, props: Props) => any;
}

export declare type ComponentOptionsWithObjectProps<PropsOptions = ComponentObjectPropsOptions, Props = ExtractPropTypes<PropsOptions>> 
  = ComponentOptionsBase<Props> & { props: PropsOptions };

export declare function defineComponent<PropsOptions extends ComponentPropsOptions>(options: ComponentOptionsWithObjectProps<PropsOptions>): any;

Playground



from Recent Questions - Stack Overflow https://ift.tt/3y3IbVj
https://ift.tt/eA8V8J

No comments:

Post a Comment