Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit eadafd2

Browse filesBrowse files
authored
Merge pull request microsoft#16346 from Microsoft/fix15618
Improve contextual types using jsdoc tags
2 parents 025fa87 + ff1f337 commit eadafd2
Copy full SHA for eadafd2

10 files changed

+350-108Lines changed: 350 additions & 108 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/checker.ts‎

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+84-84Lines changed: 84 additions & 84 deletions
Large diffs are not rendered by default.
Collapse file

‎src/compiler/utilities.ts‎

Copy file name to clipboardExpand all lines: src/compiler/utilities.ts
+48-3Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,11 @@ namespace ts {
15701570
return getFirstJSDocTag(node, SyntaxKind.JSDocReturnTag) as JSDocReturnTag;
15711571
}
15721572

1573+
export function getJSDocReturnType(node: Node): JSDocType {
1574+
const returnTag = getJSDocReturnTag(node);
1575+
return returnTag && returnTag.typeExpression && returnTag.typeExpression.type;
1576+
}
1577+
15731578
export function getJSDocTemplateTag(node: Node): JSDocTemplateTag {
15741579
return getFirstJSDocTag(node, SyntaxKind.JSDocTemplateTag) as JSDocTemplateTag;
15751580
}
@@ -2615,14 +2620,19 @@ namespace ts {
26152620
});
26162621
}
26172622

2618-
/** Get the type annotaion for the value parameter. */
2619-
export function getSetAccessorTypeAnnotationNode(accessor: SetAccessorDeclaration): TypeNode {
2623+
function getSetAccessorValueParameter(accessor: SetAccessorDeclaration): ParameterDeclaration | undefined {
26202624
if (accessor && accessor.parameters.length > 0) {
26212625
const hasThis = accessor.parameters.length === 2 && parameterIsThisKeyword(accessor.parameters[0]);
2622-
return accessor.parameters[hasThis ? 1 : 0].type;
2626+
return accessor.parameters[hasThis ? 1 : 0];
26232627
}
26242628
}
26252629

2630+
/** Get the type annotation for the value parameter. */
2631+
export function getSetAccessorTypeAnnotationNode(accessor: SetAccessorDeclaration): TypeNode {
2632+
const parameter = getSetAccessorValueParameter(accessor);
2633+
return parameter && parameter.type;
2634+
}
2635+
26262636
export function getThisParameter(signature: SignatureDeclaration): ParameterDeclaration | undefined {
26272637
if (signature.parameters.length) {
26282638
const thisParameter = signature.parameters[0];
@@ -2701,6 +2711,41 @@ namespace ts {
27012711
};
27022712
}
27032713

2714+
/**
2715+
* Gets the effective type annotation of a variable, parameter, or property. If the node was
2716+
* parsed in a JavaScript file, gets the type annotation from JSDoc.
2717+
*/
2718+
export function getEffectiveTypeAnnotationNode(node: VariableLikeDeclaration): TypeNode {
2719+
if (node.type) {
2720+
return node.type;
2721+
}
2722+
if (node.flags & NodeFlags.JavaScriptFile) {
2723+
return getJSDocType(node);
2724+
}
2725+
}
2726+
2727+
/**
2728+
* Gets the effective return type annotation of a signature. If the node was parsed in a
2729+
* JavaScript file, gets the return type annotation from JSDoc.
2730+
*/
2731+
export function getEffectiveReturnTypeNode(node: SignatureDeclaration): TypeNode {
2732+
if (node.type) {
2733+
return node.type;
2734+
}
2735+
if (node.flags & NodeFlags.JavaScriptFile) {
2736+
return getJSDocReturnType(node);
2737+
}
2738+
}
2739+
2740+
/**
2741+
* Gets the effective type annotation of the value parameter of a set accessor. If the node
2742+
* was parsed in a JavaScript file, gets the type annotation from JSDoc.
2743+
*/
2744+
export function getEffectiveSetAccessorTypeAnnotationNode(node: SetAccessorDeclaration): TypeNode {
2745+
const parameter = getSetAccessorValueParameter(node);
2746+
return parameter && getEffectiveTypeAnnotationNode(parameter);
2747+
}
2748+
27042749
export function emitNewLineBeforeLeadingComments(lineMap: number[], writer: EmitTextWriter, node: TextRange, leadingComments: CommentRange[]) {
27052750
emitNewLineBeforeLeadingCommentsOfPosition(lineMap, writer, node.pos, leadingComments);
27062751
}
Collapse file
+25Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
tests/cases/conformance/jsdoc/returns.js(6,5): error TS2322: Type '5' is not assignable to type 'string'.
2+
tests/cases/conformance/jsdoc/returns.js(13,5): error TS2322: Type 'true | 5' is not assignable to type 'string | number'.
3+
Type 'true' is not assignable to type 'string | number'.
4+
5+
6+
==== tests/cases/conformance/jsdoc/returns.js (2 errors) ====
7+
// @ts-check
8+
/**
9+
* @returns {string} This comment is not currently exposed
10+
*/
11+
function f() {
12+
return 5;
13+
~~~~~~~~~
14+
!!! error TS2322: Type '5' is not assignable to type 'string'.
15+
}
16+
17+
/**
18+
* @returns {string | number} This comment is not currently exposed
19+
*/
20+
function f1() {
21+
return 5 || true;
22+
~~~~~~~~~~~~~~~~~
23+
!!! error TS2322: Type 'true | 5' is not assignable to type 'string | number'.
24+
!!! error TS2322: Type 'true' is not assignable to type 'string | number'.
25+
}
Collapse file

‎tests/baselines/reference/checkJsdocTypeTag1.types‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/checkJsdocTypeTag1.types
+8-8Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ x(1);
6161
/** @type {function (number)} */
6262
const x1 = (a) => a + 1;
6363
>x1 : (arg0: number) => any
64-
>(a) => a + 1 : (a: any) => any
65-
>a : any
66-
>a + 1 : any
67-
>a : any
64+
>(a) => a + 1 : (a: number) => number
65+
>a : number
66+
>a + 1 : number
67+
>a : number
6868
>1 : 1
6969

7070
x1(0);
@@ -75,10 +75,10 @@ x1(0);
7575
/** @type {function (number): number} */
7676
const x2 = (a) => a + 1;
7777
>x2 : (arg0: number) => number
78-
>(a) => a + 1 : (a: any) => any
79-
>a : any
80-
>a + 1 : any
81-
>a : any
78+
>(a) => a + 1 : (a: number) => number
79+
>a : number
80+
>a + 1 : number
81+
>a : number
8282
>1 : 1
8383

8484
x2(0);
Collapse file

‎tests/baselines/reference/checkJsdocTypeTag2.errors.txt‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/checkJsdocTypeTag2.errors.txt
+13-7Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
tests/cases/conformance/jsdoc/0.js(3,5): error TS2322: Type 'true' is not assignable to type 'string'.
22
tests/cases/conformance/jsdoc/0.js(6,5): error TS2322: Type '"hello"' is not assignable to type 'number'.
33
tests/cases/conformance/jsdoc/0.js(10,4): error TS2345: Argument of type '"string"' is not assignable to parameter of type 'number'.
4-
tests/cases/conformance/jsdoc/0.js(13,7): error TS2451: Cannot redeclare block-scoped variable 'x2'.
54
tests/cases/conformance/jsdoc/0.js(17,1): error TS2322: Type 'number' is not assignable to type 'string'.
6-
tests/cases/conformance/jsdoc/0.js(20,7): error TS2451: Cannot redeclare block-scoped variable 'x2'.
5+
tests/cases/conformance/jsdoc/0.js(20,21): error TS2339: Property 'concat' does not exist on type 'number'.
6+
tests/cases/conformance/jsdoc/0.js(24,7): error TS2322: Type '(a: number) => number' is not assignable to type '(arg0: number) => string'.
7+
Type 'number' is not assignable to type 'string'.
78

89

910
==== tests/cases/conformance/jsdoc/0.js (6 errors) ====
@@ -26,8 +27,6 @@ tests/cases/conformance/jsdoc/0.js(20,7): error TS2451: Cannot redeclare block-s
2627

2728
/** @type {function (number): number} */
2829
const x2 = (a) => a + 1;
29-
~~
30-
!!! error TS2451: Cannot redeclare block-scoped variable 'x2'.
3130

3231
/** @type {string} */
3332
var a;
@@ -36,7 +35,14 @@ tests/cases/conformance/jsdoc/0.js(20,7): error TS2451: Cannot redeclare block-s
3635
!!! error TS2322: Type 'number' is not assignable to type 'string'.
3736

3837
/** @type {function (number): number} */
39-
const x2 = (a) => a.concat("hi");
38+
const x3 = (a) => a.concat("hi");
39+
~~~~~~
40+
!!! error TS2339: Property 'concat' does not exist on type 'number'.
41+
x3(0);
42+
43+
/** @type {function (number): string} */
44+
const x4 = (a) => a + 1;
4045
~~
41-
!!! error TS2451: Cannot redeclare block-scoped variable 'x2'.
42-
x2(0);
46+
!!! error TS2322: Type '(a: number) => number' is not assignable to type '(arg0: number) => string'.
47+
!!! error TS2322: Type 'number' is not assignable to type 'string'.
48+
x4(0);
Collapse file

‎tests/baselines/reference/checkJsdocTypeTag2.js‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/checkJsdocTypeTag2.js
+11-4Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@ var a;
1818
a = x2(0);
1919

2020
/** @type {function (number): number} */
21-
const x2 = (a) => a.concat("hi");
22-
x2(0);
21+
const x3 = (a) => a.concat("hi");
22+
x3(0);
23+
24+
/** @type {function (number): string} */
25+
const x4 = (a) => a + 1;
26+
x4(0);
2327

2428
//// [0.js]
2529
// @ts-check
@@ -36,5 +40,8 @@ var x2 = function (a) { return a + 1; };
3640
var a;
3741
a = x2(0);
3842
/** @type {function (number): number} */
39-
var x2 = function (a) { return a.concat("hi"); };
40-
x2(0);
43+
var x3 = function (a) { return a.concat("hi"); };
44+
x3(0);
45+
/** @type {function (number): string} */
46+
var x4 = function (a) { return a + 1; };
47+
x4(0);
Collapse file
+48Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
=== tests/cases/conformance/types/contextualTypes/jsdoc/index.js ===
2+
/** @type {Array<[string, {x?:number, y?:number}]>} */
3+
const arr = [
4+
>arr : Symbol(arr, Decl(index.js, 1, 5))
5+
6+
['a', { x: 1 }],
7+
>x : Symbol(x, Decl(index.js, 2, 11))
8+
9+
['b', { y: 2 }]
10+
>y : Symbol(y, Decl(index.js, 3, 11))
11+
12+
];
13+
14+
/** @return {Array<[string, {x?:number, y?:number}]>} */
15+
function f() {
16+
>f : Symbol(f, Decl(index.js, 4, 2))
17+
18+
return [
19+
['a', { x: 1 }],
20+
>x : Symbol(x, Decl(index.js, 9, 15))
21+
22+
['b', { y: 2 }]
23+
>y : Symbol(y, Decl(index.js, 10, 15))
24+
25+
];
26+
}
27+
28+
class C {
29+
>C : Symbol(C, Decl(index.js, 12, 1))
30+
31+
/** @param {Array<[string, {x?:number, y?:number}]>} value */
32+
set x(value) { }
33+
>x : Symbol(C.x, Decl(index.js, 14, 9), Decl(index.js, 16, 20))
34+
>value : Symbol(value, Decl(index.js, 16, 10))
35+
36+
get x() {
37+
>x : Symbol(C.x, Decl(index.js, 14, 9), Decl(index.js, 16, 20))
38+
39+
return [
40+
['a', { x: 1 }],
41+
>x : Symbol(x, Decl(index.js, 19, 19))
42+
43+
['b', { y: 2 }]
44+
>y : Symbol(y, Decl(index.js, 20, 19))
45+
46+
];
47+
}
48+
}
Collapse file
+77Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
=== tests/cases/conformance/types/contextualTypes/jsdoc/index.js ===
2+
/** @type {Array<[string, {x?:number, y?:number}]>} */
3+
const arr = [
4+
>arr : [string, { x?: number; y?: number; }][]
5+
>[ ['a', { x: 1 }], ['b', { y: 2 }]] : ([string, { x: number; }] | [string, { y: number; }])[]
6+
7+
['a', { x: 1 }],
8+
>['a', { x: 1 }] : [string, { x: number; }]
9+
>'a' : "a"
10+
>{ x: 1 } : { x: number; }
11+
>x : number
12+
>1 : 1
13+
14+
['b', { y: 2 }]
15+
>['b', { y: 2 }] : [string, { y: number; }]
16+
>'b' : "b"
17+
>{ y: 2 } : { y: number; }
18+
>y : number
19+
>2 : 2
20+
21+
];
22+
23+
/** @return {Array<[string, {x?:number, y?:number}]>} */
24+
function f() {
25+
>f : () => [string, { x?: number; y?: number; }][]
26+
27+
return [
28+
>[ ['a', { x: 1 }], ['b', { y: 2 }] ] : ([string, { x: number; }] | [string, { y: number; }])[]
29+
30+
['a', { x: 1 }],
31+
>['a', { x: 1 }] : [string, { x: number; }]
32+
>'a' : "a"
33+
>{ x: 1 } : { x: number; }
34+
>x : number
35+
>1 : 1
36+
37+
['b', { y: 2 }]
38+
>['b', { y: 2 }] : [string, { y: number; }]
39+
>'b' : "b"
40+
>{ y: 2 } : { y: number; }
41+
>y : number
42+
>2 : 2
43+
44+
];
45+
}
46+
47+
class C {
48+
>C : C
49+
50+
/** @param {Array<[string, {x?:number, y?:number}]>} value */
51+
set x(value) { }
52+
>x : [string, { x?: number; y?: number; }][]
53+
>value : [string, { x?: number; y?: number; }][]
54+
55+
get x() {
56+
>x : [string, { x?: number; y?: number; }][]
57+
58+
return [
59+
>[ ['a', { x: 1 }], ['b', { y: 2 }] ] : ([string, { x: number; }] | [string, { y: number; }])[]
60+
61+
['a', { x: 1 }],
62+
>['a', { x: 1 }] : [string, { x: number; }]
63+
>'a' : "a"
64+
>{ x: 1 } : { x: number; }
65+
>x : number
66+
>1 : 1
67+
68+
['b', { y: 2 }]
69+
>['b', { y: 2 }] : [string, { y: number; }]
70+
>'b' : "b"
71+
>{ y: 2 } : { y: number; }
72+
>y : number
73+
>2 : 2
74+
75+
];
76+
}
77+
}
Collapse file

‎tests/cases/conformance/jsdoc/checkJsdocTypeTag2.ts‎

Copy file name to clipboardExpand all lines: tests/cases/conformance/jsdoc/checkJsdocTypeTag2.ts
+6-2Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,9 @@ var a;
2121
a = x2(0);
2222

2323
/** @type {function (number): number} */
24-
const x2 = (a) => a.concat("hi");
25-
x2(0);
24+
const x3 = (a) => a.concat("hi");
25+
x3(0);
26+
27+
/** @type {function (number): string} */
28+
const x4 = (a) => a + 1;
29+
x4(0);
Collapse file
+30Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// @allowJs: true
2+
// @checkJs: true
3+
// @noEmit: true
4+
// @filename: index.js
5+
// @target: esnext
6+
7+
/** @type {Array<[string, {x?:number, y?:number}]>} */
8+
const arr = [
9+
['a', { x: 1 }],
10+
['b', { y: 2 }]
11+
];
12+
13+
/** @return {Array<[string, {x?:number, y?:number}]>} */
14+
function f() {
15+
return [
16+
['a', { x: 1 }],
17+
['b', { y: 2 }]
18+
];
19+
}
20+
21+
class C {
22+
/** @param {Array<[string, {x?:number, y?:number}]>} value */
23+
set x(value) { }
24+
get x() {
25+
return [
26+
['a', { x: 1 }],
27+
['b', { y: 2 }]
28+
];
29+
}
30+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.