Skip to content

Commit

Permalink
Merge pull request #16178 from Microsoft/master-fix13306
Browse files Browse the repository at this point in the history
[Master] Fix #13306 recognize @type on property assignment
  • Loading branch information
yuit authored Jun 22, 2017
2 parents aac7fb7 + 9df2931 commit 3ade89c
Show file tree
Hide file tree
Showing 9 changed files with 387 additions and 10 deletions.
17 changes: 11 additions & 6 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12693,12 +12693,6 @@ namespace ts {
if (typeNode) {
return getTypeFromTypeNode(typeNode);
}
if (isInJavaScriptFile(declaration)) {
const jsDocType = getTypeForDeclarationFromJSDocComment(declaration);
if (jsDocType) {
return jsDocType;
}
}
if (declaration.kind === SyntaxKind.Parameter) {
const type = getContextuallyTypedParameterType(<ParameterDeclaration>declaration);
if (type) {
Expand Down Expand Up @@ -13306,6 +13300,7 @@ namespace ts {
let patternWithComputedProperties = false;
let hasComputedStringProperty = false;
let hasComputedNumberProperty = false;
const isInJSFile = isInJavaScriptFile(node);

let offset = 0;
for (let i = 0; i < node.properties.length; i++) {
Expand All @@ -13314,6 +13309,11 @@ namespace ts {
if (memberDecl.kind === SyntaxKind.PropertyAssignment ||
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ||
isObjectLiteralMethod(memberDecl)) {
let jsdocType: Type;
if (isInJSFile) {
jsdocType = getTypeForDeclarationFromJSDocComment(memberDecl);
}

let type: Type;
if (memberDecl.kind === SyntaxKind.PropertyAssignment) {
type = checkPropertyAssignment(<PropertyAssignment>memberDecl, checkMode);
Expand All @@ -13326,6 +13326,11 @@ namespace ts {
type = checkExpressionForMutableLocation((<ShorthandPropertyAssignment>memberDecl).name, checkMode);
}

if (jsdocType) {
checkTypeAssignableTo(type, jsdocType, memberDecl);
type = jsdocType;
}

typeFlags |= type.flags;
const prop = createSymbol(SymbolFlags.Property | member.flags, member.name);
if (inDestructuringPattern) {
Expand Down
8 changes: 4 additions & 4 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2664,11 +2664,11 @@ namespace ts {
* Gets the effective type annotation of a variable, parameter, or property. If the node was
* parsed in a JavaScript file, gets the type annotation from JSDoc.
*/
export function getEffectiveTypeAnnotationNode(node: VariableLikeDeclaration): TypeNode {
export function getEffectiveTypeAnnotationNode(node: VariableLikeDeclaration): TypeNode | undefined {
if (node.type) {
return node.type;
}
if (node.flags & NodeFlags.JavaScriptFile) {
if (isInJavaScriptFile(node)) {
return getJSDocType(node);
}
}
Expand All @@ -2677,11 +2677,11 @@ namespace ts {
* Gets the effective return type annotation of a signature. If the node was parsed in a
* JavaScript file, gets the return type annotation from JSDoc.
*/
export function getEffectiveReturnTypeNode(node: SignatureDeclaration): TypeNode {
export function getEffectiveReturnTypeNode(node: SignatureDeclaration): TypeNode | undefined {
if (node.type) {
return node.type;
}
if (node.flags & NodeFlags.JavaScriptFile) {
if (isInJavaScriptFile(node)) {
return getJSDocReturnType(node);
}
}
Expand Down
53 changes: 53 additions & 0 deletions tests/baselines/reference/checkJsdocTypeTagOnObjectProperty1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//// [0.js]
// @ts-check
var lol = "hello Lol"
const obj = {
/** @type {string|undefined} */
foo: undefined,
/** @type {string|undefined} */
bar: "42",
/** @type {function(number): number} */
method1(n1) {
return n1 + 42;
},
/** @type {string} */
lol,
/** @type {number} */
['b' + 'ar1']: 42,
/** @type {function(number): number} */
arrowFunc: (num) => num + 42
}
obj.foo = 'string'
obj.lol
obj.bar = undefined;
var k = obj.method1(0);
obj.bar1 = "42";
obj.arrowFunc(0);

//// [0.js]
// @ts-check
var lol = "hello Lol";
var obj = (_a = {
/** @type {string|undefined} */
foo: undefined,
/** @type {string|undefined} */
bar: "42",
/** @type {function(number): number} */
method1: function (n1) {
return n1 + 42;
},
/** @type {string} */
lol: lol
},
/** @type {number} */
_a['b' + 'ar1'] = 42,
/** @type {function(number): number} */
_a.arrowFunc = function (num) { return num + 42; },
_a);
obj.foo = 'string';
obj.lol;
obj.bar = undefined;
var k = obj.method1(0);
obj.bar1 = "42";
obj.arrowFunc(0);
var _a;
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
=== tests/cases/conformance/jsdoc/0.js ===
// @ts-check
var lol = "hello Lol"
>lol : Symbol(lol, Decl(0.js, 1, 3))

const obj = {
>obj : Symbol(obj, Decl(0.js, 2, 5))

/** @type {string|undefined} */
foo: undefined,
>foo : Symbol(foo, Decl(0.js, 2, 13))
>undefined : Symbol(undefined)

/** @type {string|undefined} */
bar: "42",
>bar : Symbol(bar, Decl(0.js, 4, 17))

/** @type {function(number): number} */
method1(n1) {
>method1 : Symbol(method1, Decl(0.js, 6, 12))
>n1 : Symbol(n1, Decl(0.js, 8, 10))

return n1 + 42;
>n1 : Symbol(n1, Decl(0.js, 8, 10))

},
/** @type {string} */
lol,
>lol : Symbol(lol, Decl(0.js, 10, 4))

/** @type {number} */
['b' + 'ar1']: 42,
/** @type {function(number): number} */
arrowFunc: (num) => num + 42
>arrowFunc : Symbol(arrowFunc, Decl(0.js, 14, 20))
>num : Symbol(num, Decl(0.js, 16, 14))
>num : Symbol(num, Decl(0.js, 16, 14))
}
obj.foo = 'string'
>obj.foo : Symbol(foo, Decl(0.js, 2, 13))
>obj : Symbol(obj, Decl(0.js, 2, 5))
>foo : Symbol(foo, Decl(0.js, 2, 13))

obj.lol
>obj.lol : Symbol(lol, Decl(0.js, 10, 4))
>obj : Symbol(obj, Decl(0.js, 2, 5))
>lol : Symbol(lol, Decl(0.js, 10, 4))

obj.bar = undefined;
>obj.bar : Symbol(bar, Decl(0.js, 4, 17))
>obj : Symbol(obj, Decl(0.js, 2, 5))
>bar : Symbol(bar, Decl(0.js, 4, 17))
>undefined : Symbol(undefined)

var k = obj.method1(0);
>k : Symbol(k, Decl(0.js, 21, 3))
>obj.method1 : Symbol(method1, Decl(0.js, 6, 12))
>obj : Symbol(obj, Decl(0.js, 2, 5))
>method1 : Symbol(method1, Decl(0.js, 6, 12))

obj.bar1 = "42";
>obj : Symbol(obj, Decl(0.js, 2, 5))

obj.arrowFunc(0);
>obj.arrowFunc : Symbol(arrowFunc, Decl(0.js, 14, 20))
>obj : Symbol(obj, Decl(0.js, 2, 5))
>arrowFunc : Symbol(arrowFunc, Decl(0.js, 14, 20))

92 changes: 92 additions & 0 deletions tests/baselines/reference/checkJsdocTypeTagOnObjectProperty1.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
=== tests/cases/conformance/jsdoc/0.js ===
// @ts-check
var lol = "hello Lol"
>lol : string
>"hello Lol" : "hello Lol"

const obj = {
>obj : { [x: string]: any; foo: string | undefined; bar: string | undefined; method1(arg0: number): number; lol: string; arrowFunc: (arg0: number) => number; }
>{ /** @type {string|undefined} */ foo: undefined, /** @type {string|undefined} */ bar: "42", /** @type {function(number): number} */ method1(n1) { return n1 + 42; }, /** @type {string} */ lol, /** @type {number} */ ['b' + 'ar1']: 42, /** @type {function(number): number} */ arrowFunc: (num) => num + 42} : { [x: string]: any; foo: string | undefined; bar: string | undefined; method1(arg0: number): number; lol: string; arrowFunc: (arg0: number) => number; }

/** @type {string|undefined} */
foo: undefined,
>foo : string | undefined
>undefined : undefined

/** @type {string|undefined} */
bar: "42",
>bar : string | undefined
>"42" : "42"

/** @type {function(number): number} */
method1(n1) {
>method1 : (n1: any) => any
>n1 : any

return n1 + 42;
>n1 + 42 : any
>n1 : any
>42 : 42

},
/** @type {string} */
lol,
>lol : string

/** @type {number} */
['b' + 'ar1']: 42,
>'b' + 'ar1' : string
>'b' : "b"
>'ar1' : "ar1"
>42 : 42

/** @type {function(number): number} */
arrowFunc: (num) => num + 42
>arrowFunc : (arg0: number) => number
>(num) => num + 42 : (num: any) => any
>num : any
>num + 42 : any
>num : any
>42 : 42
}
obj.foo = 'string'
>obj.foo = 'string' : "string"
>obj.foo : string | undefined
>obj : { [x: string]: any; foo: string | undefined; bar: string | undefined; method1(arg0: number): number; lol: string; arrowFunc: (arg0: number) => number; }
>foo : string | undefined
>'string' : "string"

obj.lol
>obj.lol : string
>obj : { [x: string]: any; foo: string | undefined; bar: string | undefined; method1(arg0: number): number; lol: string; arrowFunc: (arg0: number) => number; }
>lol : string

obj.bar = undefined;
>obj.bar = undefined : undefined
>obj.bar : string | undefined
>obj : { [x: string]: any; foo: string | undefined; bar: string | undefined; method1(arg0: number): number; lol: string; arrowFunc: (arg0: number) => number; }
>bar : string | undefined
>undefined : undefined

var k = obj.method1(0);
>k : number
>obj.method1(0) : number
>obj.method1 : (arg0: number) => number
>obj : { [x: string]: any; foo: string | undefined; bar: string | undefined; method1(arg0: number): number; lol: string; arrowFunc: (arg0: number) => number; }
>method1 : (arg0: number) => number
>0 : 0

obj.bar1 = "42";
>obj.bar1 = "42" : "42"
>obj.bar1 : any
>obj : { [x: string]: any; foo: string | undefined; bar: string | undefined; method1(arg0: number): number; lol: string; arrowFunc: (arg0: number) => number; }
>bar1 : any
>"42" : "42"

obj.arrowFunc(0);
>obj.arrowFunc(0) : number
>obj.arrowFunc : (arg0: number) => number
>obj : { [x: string]: any; foo: string | undefined; bar: string | undefined; method1(arg0: number): number; lol: string; arrowFunc: (arg0: number) => number; }
>arrowFunc : (arg0: number) => number
>0 : 0

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
tests/cases/conformance/jsdoc/0.js(5,3): error TS2322: Type 'number' is not assignable to type 'string | undefined'.
tests/cases/conformance/jsdoc/0.js(7,3): error TS2322: Type '(n1: any) => string' is not assignable to type '(arg0: number) => number'.
Type 'string' is not assignable to type 'number'.
tests/cases/conformance/jsdoc/0.js(11,3): error TS2322: Type '(n1: any) => string' is not assignable to type '(arg0: number) => number'.
Type 'string' is not assignable to type 'number'.
tests/cases/conformance/jsdoc/0.js(13,3): error TS2322: Type '(num?: string) => string' is not assignable to type '(arg0: number) => number'.
Types of parameters 'num' and 'arg0' are incompatible.
Type 'number' is not assignable to type 'string | undefined'.
tests/cases/conformance/jsdoc/0.js(15,3): error TS2322: Type 'undefined' is not assignable to type 'string'.
tests/cases/conformance/jsdoc/0.js(19,5): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/jsdoc/0.js(22,22): error TS2345: Argument of type '"0"' is not assignable to parameter of type 'number'.


==== tests/cases/conformance/jsdoc/0.js (7 errors) ====
// @ts-check
var lol;
const obj = {
/** @type {string|undefined} */
bar: 42,
~~~~~~~
!!! error TS2322: Type 'number' is not assignable to type 'string | undefined'.
/** @type {function(number): number} */
method1(n1) {
~~~~~~~
!!! error TS2322: Type '(n1: any) => string' is not assignable to type '(arg0: number) => number'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.
return "42";
},
/** @type {function(number): number} */
method2: (n1) => "lol",
~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type '(n1: any) => string' is not assignable to type '(arg0: number) => number'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.
/** @type {function(number): number} */
arrowFunc: (num="0") => num + 42,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type '(num?: string) => string' is not assignable to type '(arg0: number) => number'.
!!! error TS2322: Types of parameters 'num' and 'arg0' are incompatible.
!!! error TS2322: Type 'number' is not assignable to type 'string | undefined'.
/** @type {string} */
lol
~~~
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
}
lol = "string"
/** @type {string} */
var s = obj.method1(0);
~
!!! error TS2322: Type 'number' is not assignable to type 'string'.

/** @type {string} */
var s1 = obj.method2("0");
~~~
!!! error TS2345: Argument of type '"0"' is not assignable to parameter of type 'number'.
49 changes: 49 additions & 0 deletions tests/baselines/reference/checkJsdocTypeTagOnObjectProperty2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//// [0.js]
// @ts-check
var lol;
const obj = {
/** @type {string|undefined} */
bar: 42,
/** @type {function(number): number} */
method1(n1) {
return "42";
},
/** @type {function(number): number} */
method2: (n1) => "lol",
/** @type {function(number): number} */
arrowFunc: (num="0") => num + 42,
/** @type {string} */
lol
}
lol = "string"
/** @type {string} */
var s = obj.method1(0);

/** @type {string} */
var s1 = obj.method2("0");

//// [0.js]
// @ts-check
var lol;
var obj = {
/** @type {string|undefined} */
bar: 42,
/** @type {function(number): number} */
method1: function (n1) {
return "42";
},
/** @type {function(number): number} */
method2: function (n1) { return "lol"; },
/** @type {function(number): number} */
arrowFunc: function (num) {
if (num === void 0) { num = "0"; }
return num + 42;
},
/** @type {string} */
lol: lol
};
lol = "string";
/** @type {string} */
var s = obj.method1(0);
/** @type {string} */
var s1 = obj.method2("0");
Loading

0 comments on commit 3ade89c

Please sign in to comment.