mirror of https://github.com/vuejs/core.git
fix(defineModel): align prod mode runtime type generation with defineProps
close #10769
This commit is contained in:
parent
3724693a25
commit
4253a57f17
|
@ -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 }
|
||||
}
|
||||
|
||||
})"
|
||||
`;
|
||||
|
|
|
@ -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(
|
||||
`
|
||||
|
|
|
@ -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},`
|
||||
|
||||
|
|
Loading…
Reference in New Issue