Vue version
3.5.39
Link to minimal reproduction
https://play.vuejs.org/#eNqtk81qGzEQx19l0MUJmDXUTaGLbUhKDi20DY1JD1Gold3ZjWJZEvpwbcwee+sjtC/XJ+lIi50EQk65rWb+M/Obj92xU2uLdURWsomvnLQBPIZoQQndTjkLnrMZ13JljQsQthZhBxfO2Hn67KBxZgUDSjDgmuvRCP79/Q1nsS1hfglSN+g8zHtVuENY1NiIqMICGlEF47Ygg0fVkNQHFDWYBhapymKYs1UieqlbEOBtdNJE3zOgc8YBuSqEq4gwLk6K8fuC68pQIrh1ZokapkDlpMbPpkZ1NFhLL2+lkmE7GMKOa8i5Sjh1TmxB+ENfEx8cVb2+mREFpCSJuYSjY5jO4PqGrN3xvt8/v+C7cUvhTNR1CVbq3GmLGp2sADdWyUoGtd3DNXKD9VO2h4KPKd+8DuZk1C+W1kiPgCurREB6AUxquZ7tdvt5dR3Qo+fruskoeVP8IYYN6SCoi0a2xb03mq4mA3JWmZWVCt1XGyR1yVnZoyefUMr8/JRtwUXMsDnmDqvlM/Z7v0k2zi4cenRr5OzgC8K1GHr3+eUX3ND3wbkydVSkfsH5Db1RMTH2sjNaGmE/0mXaj/neabhzf74JqP2+qQSalF3Wc0aX/+GF1h9wx8XbHEc7oSn+WNOPQWoaYH+6yRb81cF6Urwrxqz7D9k1OqM=
Steps to reproduce
In the reproduction, broken declares a named model with a runtime type: PropType<string[]> plus a factory default: () => []. fixed declares the same thing but with the generic pinned explicitly (defineModel<string[]>(...)).
Run the type checker (or vue-tsc --noEmit locally) over this SFC.
What is expected?
Both broken and fixed should type-check cleanly — this is the recommended pattern for avoiding shared mutable state (per #14966 / #14968): a factory default combined with a runtime PropType declaration.
What is actually happening?
Only broken fails. TS infers the generic T from the default factory function's own type (() => never[]) instead of from the type: PropType<string[]> field:
error TS2769: No overload matches this call.
Overload 1 of 4, '(name: string, options: ({ required: true; } | { default: DefineModelDefault<() => never[]>; }) & Omit<PropOptions<() => never[], () => never[]>, "default"> & DefineModelOptions<...>): ModelRef<...>', gave the following error.
Type 'PropType<string[]>' is not assignable to type 'true | PropType<() => never[]> | null | undefined'.
Type 'new (...args: any[]) => string[]' is not assignable to type 'true | PropType<() => never[]> | null | undefined'.
Type 'new (...args: any[]) => string[]' is not assignable to type 'new (...args: any[]) => () => never[]'.
Type 'string[]' is not assignable to type '() => never[]'.
Type 'string[]' provides no match for the signature '(): never[]'.
Overload 2 of 4, '(name: string, options?: DefineModelRuntimeOptions<string[], string[], string[]> | undefined): ModelRef<string[] | undefined, string, string[] | undefined, string[] | undefined>', gave the following error.
Object literal may only specify known properties, and 'default' does not exist in type 'DefineModelRuntimeOptions<string[], string[], string[]>'.
his is a regression from #14968 (landed in 3.5.39), which introduced DefineModelDefault<T> = InferDefault<Data, T> for the named-model overload. When both a runtime type: PropType<T> field and a factory default are present on the same options object, TS resolves T from the default field first, breaking a pattern that worked prior to 3.5.39.
Workaround: explicitly pin the generic, as shown by fixed in the reproduction:
const fixed = defineModel<string[]>('visibility2', {
type: Array as PropType<string[]>,
default: () => [],
})
System Info
vue: 3.5.39
vue-tsc: 3.3.7
typescript: 5.7.3
Any additional comments?
Related to / regression from #14966 and #14968. Only reproduces on the named defineModel(name, options) overload when type/PropType and a factory default are combined; the unnamed defineModel<T>({ ... }) form with an explicit generic is unaffected.
Vue version
3.5.39
Link to minimal reproduction
https://play.vuejs.org/#eNqtk81qGzEQx19l0MUJmDXUTaGLbUhKDi20DY1JD1Gold3ZjWJZEvpwbcwee+sjtC/XJ+lIi50EQk65rWb+M/Obj92xU2uLdURWsomvnLQBPIZoQQndTjkLnrMZ13JljQsQthZhBxfO2Hn67KBxZgUDSjDgmuvRCP79/Q1nsS1hfglSN+g8zHtVuENY1NiIqMICGlEF47Ygg0fVkNQHFDWYBhapymKYs1UieqlbEOBtdNJE3zOgc8YBuSqEq4gwLk6K8fuC68pQIrh1ZokapkDlpMbPpkZ1NFhLL2+lkmE7GMKOa8i5Sjh1TmxB+ENfEx8cVb2+mREFpCSJuYSjY5jO4PqGrN3xvt8/v+C7cUvhTNR1CVbq3GmLGp2sADdWyUoGtd3DNXKD9VO2h4KPKd+8DuZk1C+W1kiPgCurREB6AUxquZ7tdvt5dR3Qo+fruskoeVP8IYYN6SCoi0a2xb03mq4mA3JWmZWVCt1XGyR1yVnZoyefUMr8/JRtwUXMsDnmDqvlM/Z7v0k2zi4cenRr5OzgC8K1GHr3+eUX3ND3wbkydVSkfsH5Db1RMTH2sjNaGmE/0mXaj/neabhzf74JqP2+qQSalF3Wc0aX/+GF1h9wx8XbHEc7oSn+WNOPQWoaYH+6yRb81cF6Urwrxqz7D9k1OqM=
Steps to reproduce
In the reproduction,
brokendeclares a named model with a runtimetype: PropType<string[]>plus a factorydefault: () => [].fixeddeclares the same thing but with the generic pinned explicitly (defineModel<string[]>(...)).Run the type checker (or
vue-tsc --noEmitlocally) over this SFC.What is expected?
Both
brokenandfixedshould type-check cleanly — this is the recommended pattern for avoiding shared mutable state (per #14966 / #14968): a factory default combined with a runtimePropTypedeclaration.What is actually happening?
Only
brokenfails. TS infers the genericTfrom thedefaultfactory function's own type (() => never[]) instead of from thetype: PropType<string[]>field:error TS2769: No overload matches this call.
Overload 1 of 4, '(name: string, options: ({ required: true; } | { default: DefineModelDefault<() => never[]>; }) & Omit<PropOptions<() => never[], () => never[]>, "default"> & DefineModelOptions<...>): ModelRef<...>', gave the following error.
Type 'PropType<string[]>' is not assignable to type 'true | PropType<() => never[]> | null | undefined'.
Type 'new (...args: any[]) => string[]' is not assignable to type 'true | PropType<() => never[]> | null | undefined'.
Type 'new (...args: any[]) => string[]' is not assignable to type 'new (...args: any[]) => () => never[]'.
Type 'string[]' is not assignable to type '() => never[]'.
Type 'string[]' provides no match for the signature '(): never[]'.
Overload 2 of 4, '(name: string, options?: DefineModelRuntimeOptions<string[], string[], string[]> | undefined): ModelRef<string[] | undefined, string, string[] | undefined, string[] | undefined>', gave the following error.
Object literal may only specify known properties, and 'default' does not exist in type 'DefineModelRuntimeOptions<string[], string[], string[]>'.
his is a regression from #14968 (landed in 3.5.39), which introduced
DefineModelDefault<T> = InferDefault<Data, T>for the named-model overload. When both a runtimetype: PropType<T>field and a factorydefaultare present on the same options object, TS resolvesTfrom thedefaultfield first, breaking a pattern that worked prior to 3.5.39.Workaround: explicitly pin the generic, as shown by
fixedin the reproduction:System Info
Any additional comments?
Related to / regression from #14966 and #14968. Only reproduces on the named
defineModel(name, options)overload whentype/PropTypeand a factorydefaultare combined; the unnameddefineModel<T>({ ... })form with an explicit generic is unaffected.