Skip to content

Commit 457ef3c

Browse files
committed
feat: add experimentalAllowTypeNarrowingInInlineHandlers option
close #1249
1 parent 221404d commit 457ef3c

File tree

4 files changed

+35
-4
lines changed

4 files changed

+35
-4
lines changed

extensions/vscode-vue-language-features/schemas/vue-tsconfig.schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
"type": "boolean",
3737
"markdownDescription": "https://github.com/johnsoncodehk/volar/issues/577"
3838
},
39+
"experimentalAllowTypeNarrowingInInlineHandlers": {
40+
"type": "boolean",
41+
"markdownDescription": "https://github.com/johnsoncodehk/volar/issues/1249"
42+
},
3943
"experimentalResolveStyleCssClasses": {
4044
"enum": [
4145
"scoped",

packages/vue-code-gen/src/generators/template.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ export function generate(
4949
sourceLang: string,
5050
templateAst: CompilerDOM.RootNode,
5151
isVue2: boolean,
52+
allowTypeNarrowingInEventExpressions: boolean,
5253
cssScopedClasses: string[] = [],
5354
htmlToTemplate: (htmlStart: number, htmlEnd: number) => { start: number, end: number; } | undefined,
54-
isScriptSetup: boolean,
5555
searchTexts: {
5656
getEmitCompletion(tag: string): string,
5757
getPropsCompletion(tag: string): string,
@@ -91,6 +91,7 @@ export function generate(
9191
const localVars: Record<string, number> = {};
9292
const identifiers = new Set<string>();
9393
const scopedClasses: { className: string, offset: number; }[] = [];
94+
const blockConditions: string[] = [];
9495

9596
tsFormatCodeGen.addText('export { };\n');
9697

@@ -393,6 +394,9 @@ export function generate(
393394
}
394395
else if (node.type === CompilerDOM.NodeTypes.IF) {
395396
// v-if / v-else-if / v-else
397+
398+
let originalBlockConditionsLength = blockConditions.length;
399+
396400
for (let i = 0; i < node.branches.length; i++) {
397401

398402
const branch = node.branches[i];
@@ -404,6 +408,8 @@ export function generate(
404408
else
405409
tsCodeGen.addText('else');
406410

411+
let addedBlockCondition = false;
412+
407413
if (branch.condition?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
408414
tsCodeGen.addText(` `);
409415
writeInterpolation(
@@ -421,13 +427,24 @@ export function generate(
421427
branch.condition.loc.start.offset,
422428
formatBrackets.round,
423429
);
430+
431+
if (allowTypeNarrowingInEventExpressions) {
432+
blockConditions.push(branch.condition.content);
433+
addedBlockCondition = true;
434+
}
424435
}
425436
tsCodeGen.addText(` {\n`);
426437
for (const childNode of branch.children) {
427438
visitNode(childNode, parentEl);
428439
}
429440
tsCodeGen.addText('}\n');
441+
442+
if (addedBlockCondition) {
443+
blockConditions[blockConditions.length - 1] = `!(${blockConditions[blockConditions.length - 1]})`;
444+
}
430445
}
446+
447+
blockConditions.length = originalBlockConditionsLength;
431448
}
432449
else if (node.type === CompilerDOM.NodeTypes.FOR) {
433450
// v-for
@@ -747,8 +764,17 @@ export function generate(
747764
const _exp = prop.exp;
748765
const expIndex = jsChildNode.children.findIndex(child => typeof child === 'object' && child.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && child.content === _exp.content);
749766
const expNode = jsChildNode.children[expIndex] as CompilerDOM.SimpleExpressionNode;
750-
const prefix = jsChildNode.children.filter((child, i) => typeof child === 'string' && i < expIndex).map(child => child as string).join('');
751-
const suffix = jsChildNode.children.filter((child, i) => typeof child === 'string' && i > expIndex).map(child => child as string).join('');
767+
let prefix = jsChildNode.children.filter((child, i) => typeof child === 'string' && i < expIndex).map(child => child as string).join('');
768+
let suffix = jsChildNode.children.filter((child, i) => typeof child === 'string' && i > expIndex).map(child => child as string).join('');
769+
770+
if (prefix && blockConditions.length) {
771+
prefix = prefix.replace('(', '{ ');
772+
suffix = suffix.replace(')', '} ');
773+
prefix += '\n';
774+
for (const blockCondition of blockConditions) {
775+
prefix += `if (!(${blockCondition})) return;\n`;
776+
}
777+
}
752778

753779
writeInterpolation(
754780
expNode.content,

packages/vue-typescript/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ export interface VueCompilerOptions {
1717
experimentalTemplateCompilerOptionsRequirePath?: string;
1818
experimentalDisableTemplateSupport?: boolean;
1919
experimentalResolveStyleCssClasses?: 'scoped' | 'always' | 'never';
20+
experimentalAllowTypeNarrowingInInlineHandlers?: boolean;
2021
}

packages/vue-typescript/src/use/useSfcTemplateScript.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ export function useSfcTemplateScript(
7171
templateData.value.lang,
7272
sfcTemplateCompileResult.value.ast,
7373
compilerOptions.experimentalCompatMode === 2,
74+
!!compilerOptions.experimentalAllowTypeNarrowingInInlineHandlers,
7475
Object.values(cssScopedClasses.value).map(map => Object.keys(map)).flat(),
7576
templateData.value.htmlToTemplate,
76-
!!scriptSetup.value,
7777
{
7878
getEmitCompletion: SearchTexts.EmitCompletion,
7979
getPropsCompletion: SearchTexts.PropsCompletion,

0 commit comments

Comments
 (0)