]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(defineModel): align prod mode runtime type generation with defineProps
authorEvan You <yyx990803@gmail.com>
Wed, 24 Apr 2024 10:21:57 +0000 (18:21 +0800)
committerEvan You <yyx990803@gmail.com>
Wed, 24 Apr 2024 10:21:57 +0000 (18:21 +0800)
close #10769

packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap
packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts
packages/compiler-sfc/src/script/defineModel.ts

index 6e9967fd0116c88002ab54fdcf356a9ec646186d..6fe26a63902e85595f78ae385f4c3f0653d26d8d 100644 (file)
@@ -226,3 +226,43 @@ return { modelValue, fn, fnWithDefault, str, optional }
 
 })"
 `;
+
+exports[`defineModel() > w/ types, production mode, boolean + multiple types 1`] = `
+"import { useModel as _useModel, defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+  props: {
+    "modelValue": { type: [Boolean, String, Object] },
+    "modelModifiers": {},
+  },
+  emits: ["update:modelValue"],
+  setup(__props, { expose: __expose }) {
+  __expose();
+
+      const modelValue = _useModel<boolean | string | {}>(__props, "modelValue")
+      
+return { modelValue }
+}
+
+})"
+`;
+
+exports[`defineModel() > w/ types, production mode, function + runtime opts + multiple types 1`] = `
+"import { useModel as _useModel, defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+  props: {
+    "modelValue": { type: [Number, Function], ...{ default: () => 1 } },
+    "modelModifiers": {},
+  },
+  emits: ["update:modelValue"],
+  setup(__props, { expose: __expose }) {
+  __expose();
+
+      const modelValue = _useModel<number | (() => number)>(__props, "modelValue")
+      
+return { modelValue }
+}
+
+})"
+`;
index bd048a847e487c5de10f157e99b662fb2e30cb67..4550aa5c4c0c6459b896bf27b2e515a4aac24054 100644 (file)
@@ -161,6 +161,34 @@ describe('defineModel()', () => {
     })
   })
 
+  test('w/ types, production mode, boolean + multiple types', () => {
+    const { content } = compile(
+      `
+      <script setup lang="ts">
+      const modelValue = defineModel<boolean | string | {}>()
+      </script>
+      `,
+      { isProd: true },
+    )
+    assertCode(content)
+    expect(content).toMatch('"modelValue": { type: [Boolean, String, Object] }')
+  })
+
+  test('w/ types, production mode, function + runtime opts + multiple types', () => {
+    const { content } = compile(
+      `
+      <script setup lang="ts">
+      const modelValue = defineModel<number | (() => number)>({ default: () => 1 })
+      </script>
+      `,
+      { isProd: true },
+    )
+    assertCode(content)
+    expect(content).toMatch(
+      '"modelValue": { type: [Number, Function], ...{ default: () => 1 } }',
+    )
+  })
+
   test('get / set transformers', () => {
     const { content } = compile(
       `
index e5e2ed0e53fc3faae22ed27674852c1d65bf4b8b..05082800284667a63c61466fd83950eb898e8de2 100644 (file)
@@ -1,12 +1,7 @@
 import type { LVal, Node, TSType } from '@babel/types'
 import type { ScriptCompileContext } from './context'
 import { inferRuntimeType } from './resolveType'
-import {
-  UNKNOWN_TYPE,
-  concatStrings,
-  isCallOf,
-  toRuntimeTypeString,
-} from './utils'
+import { UNKNOWN_TYPE, isCallOf, toRuntimeTypeString } from './utils'
 import { BindingTypes, unwrapTSNode } from '@vue/compiler-dom'
 
 export const DEFINE_MODEL = 'defineModel'
@@ -124,44 +119,50 @@ export function genModelProps(ctx: ScriptCompileContext) {
 
   const isProd = !!ctx.options.isProd
   let modelPropsDecl = ''
-  for (const [name, { type, options }] of Object.entries(ctx.modelDecls)) {
+  for (const [name, { type, options: runtimeOptions }] of Object.entries(
+    ctx.modelDecls,
+  )) {
     let skipCheck = false
-
+    let codegenOptions = ``
     let runtimeTypes = type && inferRuntimeType(ctx, type)
     if (runtimeTypes) {
       const hasBoolean = runtimeTypes.includes('Boolean')
+      const hasFunction = runtimeTypes.includes('Function')
       const hasUnknownType = runtimeTypes.includes(UNKNOWN_TYPE)
 
-      if (isProd || hasUnknownType) {
-        runtimeTypes = runtimeTypes.filter(
-          t =>
-            t === 'Boolean' ||
-            (hasBoolean && t === 'String') ||
-            (t === 'Function' && options),
-        )
+      if (hasUnknownType) {
+        if (hasBoolean || hasFunction) {
+          runtimeTypes = runtimeTypes.filter(t => t !== UNKNOWN_TYPE)
+          skipCheck = true
+        } else {
+          runtimeTypes = ['null']
+        }
+      }
 
-        skipCheck = !isProd && hasUnknownType && runtimeTypes.length > 0
+      if (!isProd) {
+        codegenOptions =
+          `type: ${toRuntimeTypeString(runtimeTypes)}` +
+          (skipCheck ? ', skipCheck: true' : '')
+      } else if (hasBoolean || (runtimeOptions && hasFunction)) {
+        // preserve types if contains boolean, or
+        // function w/ runtime options that may contain default
+        codegenOptions = `type: ${toRuntimeTypeString(runtimeTypes)}`
+      } else {
+        // able to drop types in production
       }
     }
 
-    let runtimeType =
-      (runtimeTypes &&
-        runtimeTypes.length > 0 &&
-        toRuntimeTypeString(runtimeTypes)) ||
-      undefined
-
-    const codegenOptions = concatStrings([
-      runtimeType && `type: ${runtimeType}`,
-      skipCheck && 'skipCheck: true',
-    ])
-
     let decl: string
-    if (runtimeType && options) {
+    if (codegenOptions && runtimeOptions) {
       decl = ctx.isTS
-        ? `{ ${codegenOptions}, ...${options} }`
-        : `Object.assign({ ${codegenOptions} }, ${options})`
+        ? `{ ${codegenOptions}, ...${runtimeOptions} }`
+        : `Object.assign({ ${codegenOptions} }, ${runtimeOptions})`
+    } else if (codegenOptions) {
+      decl = `{ ${codegenOptions} }`
+    } else if (runtimeOptions) {
+      decl = runtimeOptions
     } else {
-      decl = options || (runtimeType ? `{ ${codegenOptions} }` : '{}')
+      decl = `{}`
     }
     modelPropsDecl += `\n    ${JSON.stringify(name)}: ${decl},`