Skip to content

Commit 21f1923

Browse files
authored
Fix infer from usage prop assignment (#33088)
* Add test case * Fix infer from usage property assignment Property assignment and shorthand property assignment were incorrectly treated differently; both have ObjectLiteralExpression as a parent, but the code previously assumed that property assignments had ObjectLiteralExpression as parent.parent. Also make fourslash directives case insensitive and less whitespace sensitive. * Add "incorrect 3-slash" error to fourslash parsing.
1 parent b4417da commit 21f1923

File tree

4 files changed

+35
-22
lines changed

4 files changed

+35
-22
lines changed

src/harness/fourslash.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ namespace FourSlash {
8080
// To add additional option, add property into the testOptMetadataNames, refer the property in either globalMetadataNames or fileMetadataNames
8181
// Add cases into convertGlobalOptionsToCompilationsSettings function for the compiler to acknowledge such option from meta data
8282
const enum MetadataOptionNames {
83-
baselineFile = "BaselineFile",
84-
emitThisFile = "emitThisFile", // This flag is used for testing getEmitOutput feature. It allows test-cases to indicate what file to be output in multiple files project
85-
fileName = "Filename",
86-
resolveReference = "ResolveReference", // This flag is used to specify entry file for resolve file references. The flag is only allow once per test file
87-
symlink = "Symlink",
83+
baselineFile = "baselinefile",
84+
emitThisFile = "emitthisfile", // This flag is used for testing getEmitOutput feature. It allows test-cases to indicate what file to be output in multiple files project
85+
fileName = "filename",
86+
resolveReference = "resolvereference", // This flag is used to specify entry file for resolve file references. The flag is only allow once per test file
87+
symlink = "symlink",
8888
}
8989

9090
// List of allowed metadata names
@@ -3281,7 +3281,7 @@ ${code}
32813281

32823282
function parseTestData(basePath: string, contents: string, fileName: string): FourSlashData {
32833283
// Regex for parsing options in the format "@Alpha: Value of any sort"
3284-
const optionRegex = /^\s*@(\w+): (.*)\s*/;
3284+
const optionRegex = /^\s*@(\w+):\s*(.*)\s*/;
32853285

32863286
// List of all the subfiles we've parsed out
32873287
const files: FourSlashFile[] = [];
@@ -3293,6 +3293,7 @@ ${code}
32933293
// Note: IE JS engine incorrectly handles consecutive delimiters here when using RegExp split, so
32943294
// we have to string-based splitting instead and try to figure out the delimiting chars
32953295
const lines = contents.split("\n");
3296+
let i = 0;
32963297

32973298
const markerPositions = ts.createMap<Marker>();
32983299
const markers: Marker[] = [];
@@ -3321,6 +3322,7 @@ ${code}
33213322
}
33223323

33233324
for (let line of lines) {
3325+
i++;
33243326
if (line.length > 0 && line.charAt(line.length - 1) === "\r") {
33253327
line = line.substr(0, line.length - 1);
33263328
}
@@ -3329,11 +3331,15 @@ ${code}
33293331
const text = line.substr(4);
33303332
currentFileContent = currentFileContent === undefined ? text : currentFileContent + "\n" + text;
33313333
}
3334+
else if (line.substr(0, 3) === "///" && currentFileContent !== undefined) {
3335+
throw new Error("Three-slash line in the middle of four-slash region at line " + i);
3336+
}
33323337
else if (line.substr(0, 2) === "//") {
33333338
// Comment line, check for global/file @options and record them
33343339
const match = optionRegex.exec(line.substr(2));
33353340
if (match) {
3336-
const [key, value] = match.slice(1);
3341+
const key = match[1].toLowerCase();
3342+
const value = match[2];
33373343
if (!ts.contains(fileMetadataNames, key)) {
33383344
// Check if the match is already existed in the global options
33393345
if (globalOptions[key] !== undefined) {

src/services/codefixes/inferFromUsage.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -717,13 +717,9 @@ namespace ts.codefix {
717717
}
718718

719719
function inferTypeFromPropertyAssignment(assignment: PropertyAssignment | ShorthandPropertyAssignment, checker: TypeChecker, usageContext: UsageContext) {
720-
const objectLiteral = isShorthandPropertyAssignment(assignment) ?
721-
assignment.parent :
722-
assignment.parent.parent;
723-
const nodeWithRealType = isVariableDeclaration(objectLiteral.parent) ?
724-
objectLiteral.parent :
725-
objectLiteral;
726-
720+
const nodeWithRealType = isVariableDeclaration(assignment.parent.parent) ?
721+
assignment.parent.parent :
722+
assignment.parent;
727723
addCandidateThisType(usageContext, checker.getTypeAtLocation(nodeWithRealType));
728724
}
729725

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/// <reference path="fourslash.ts"/>
2+
// @allowJs: true
3+
// @checkJs: true
4+
// @noEmit: true
5+
// @filename:destruct.js
6+
//// function [|formatter|](message) {
7+
//// const { type } = false ? { type: message } : message;
8+
//// }
9+
verify.codeFix({
10+
description: "Infer parameter types from usage",
11+
index: 0,
12+
newFileContent: `/**
13+
* @param {{ type: any; }} message
14+
*/
15+
function formatter(message) {
16+
const { type } = false ? { type: message } : message;
17+
}`
18+
});

tests/cases/fourslash/codeFixInferFromUsageJSXElement.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
// @module: es2015
66
// @moduleResolution: node
77

8-
// @Filename: /node_modules/@types/react/index.d.ts
9-
////export = React;
10-
////export as namespace React;
118
////declare namespace React {
129
//// export class Component { render(): JSX.Element | null; }
1310
////}
@@ -16,10 +13,6 @@
1613
//// interface Element {}
1714
//// }
1815
////}
19-
20-
21-
// @filename: a.tsx
22-
//// import React from 'react';
2316
////
2417
//// export default function Component([|props |]) {
2518
//// if (props.isLoading) {
@@ -37,4 +30,4 @@
3730
//// }
3831

3932

40-
verify.rangeAfterCodeFix("props: { isLoading: any; update: (arg0: any) => void; }",/*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, 0);
33+
verify.rangeAfterCodeFix("props: { isLoading: any; update: (arg0: any) => void; }",/*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, 0);

0 commit comments

Comments
 (0)