@@ -2105,8 +2105,75 @@ module ts {
2105
2105
return type;
2106
2106
}
2107
2107
2108
+ function getTypeForVariableLikeDeclarationFromJSDocComment(declaration: VariableLikeDeclaration) {
2109
+ // First see if this node has a doc comment on it directly.
2110
+ let jsDocType = getJSDocTypeForVariableLikeDeclarationFromJSDocComment(declaration);
2111
+ return getTypeFromJSDocType(jsDocType);
2112
+ }
2113
+
2114
+ function getJSDocTypeForVariableLikeDeclarationFromJSDocComment(declaration: VariableLikeDeclaration): JSDocType {
2115
+ // First, see if this node has an @type annotation on it directly.
2116
+ let sourceFile = getSourceFileOfNode(declaration);
2117
+ let docComment = getJSDocComment(declaration, sourceFile);
2118
+
2119
+ if (docComment && docComment.type) {
2120
+ return docComment.type;
2121
+ }
2122
+
2123
+ if (declaration.kind === SyntaxKind.VariableDeclaration &&
2124
+ declaration.parent.kind === SyntaxKind.VariableDeclarationList &&
2125
+ declaration.parent.parent.kind === SyntaxKind.VariableStatement) {
2126
+
2127
+ // @type annotation might have been on the variable statement, try that instead.
2128
+ docComment = getJSDocComment(declaration.parent.parent, sourceFile);
2129
+ if (docComment && docComment.type) {
2130
+ return docComment.type;
2131
+ }
2132
+ }
2133
+ else if (declaration.kind === SyntaxKind.Parameter && (<ParameterDeclaration>declaration).name.kind === SyntaxKind.Identifier) {
2134
+ // If it's a parameter, see if the parent has a jsdoc comment with an @param
2135
+ // annotation.
2136
+ let parameterName = (<Identifier>(<ParameterDeclaration>declaration).name).text;
2137
+
2138
+ docComment = getJSDocComment(declaration.parent, sourceFile);
2139
+ if (docComment && docComment.parameters) {
2140
+ for (let parameter of docComment.parameters) {
2141
+ if (parameter.name === parameterName) {
2142
+ return parameter.type;
2143
+ }
2144
+ }
2145
+ }
2146
+ }
2147
+
2148
+ return undefined;
2149
+ }
2150
+
2151
+ function getJSDocComment(node: Node, sourceFile: SourceFile) {
2152
+ let comments = getLeadingCommentRangesOfNode(node, sourceFile);
2153
+ if (comments) {
2154
+ for (let comment of comments) {
2155
+ let jsDocComment = parseJSDocComment(sourceFile.text, comment.pos, comment.end - comment.pos);
2156
+ if (jsDocComment) {
2157
+ return jsDocComment;
2158
+ }
2159
+ }
2160
+ }
2161
+
2162
+ return undefined;
2163
+ }
2164
+
2108
2165
// Return the inferred type for a variable, parameter, or property declaration
2109
2166
function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration): Type {
2167
+ if (declaration.parserContextFlags & ParserContextFlags.JavaScriptFile) {
2168
+ // If this is a variable in a JavaScript file, then use the JSDoc type (if it has
2169
+ // one as it's type), otherwise fallback to the below standard TS codepaths to
2170
+ // try to figure it out.
2171
+ let type = getTypeForVariableLikeDeclarationFromJSDocComment(declaration);
2172
+ if (type) {
2173
+ return type;
2174
+ }
2175
+ }
2176
+
2110
2177
// A variable declared in a for..in statement is always of type any
2111
2178
if (declaration.parent.parent.kind === SyntaxKind.ForInStatement) {
2112
2179
return anyType;
@@ -2121,6 +2188,7 @@ module ts {
2121
2188
if (isBindingPattern(declaration.parent)) {
2122
2189
return getTypeForBindingElement(<BindingElement>declaration);
2123
2190
}
2191
+
2124
2192
// Use type from type annotation if one is present
2125
2193
if (declaration.type) {
2126
2194
return getTypeFromTypeNodeOrHeritageClauseElement(declaration.type);
@@ -3618,6 +3686,79 @@ module ts {
3618
3686
return links.resolvedType;
3619
3687
}
3620
3688
3689
+ function getTypeFromJSDocType(jsDocType: JSDocType): Type {
3690
+ if (jsDocType) {
3691
+ switch (jsDocType.kind) {
3692
+ case SyntaxKind.JSDocAllType:
3693
+ return anyType;
3694
+ case SyntaxKind.JSDocUnknownType:
3695
+ return unknownType;
3696
+ case SyntaxKind.JSDocUnionType:
3697
+ return getTypeFromJSDocUnionType(<JSDocUnionType>jsDocType);
3698
+ case SyntaxKind.JSDocNullableType:
3699
+ return getTypeFromJSDocType((<JSDocNullableType>jsDocType).type);
3700
+ case SyntaxKind.JSDocNonNullableType:
3701
+ return getTypeFromJSDocType((<JSDocNonNullableType>jsDocType).type);
3702
+ case SyntaxKind.JSDocRecordType:
3703
+ // NYI:
3704
+ break;
3705
+ case SyntaxKind.JSDocTypeReference:
3706
+ return getTypeForJSDocTypeReference(<JSDocTypeReference>jsDocType);
3707
+ case SyntaxKind.JSDocOptionalType:
3708
+ return getTypeFromJSDocType((<JSDocOptionalType>jsDocType).type);
3709
+ case SyntaxKind.JSDocFunctionType:
3710
+ // NYI:
3711
+ break;
3712
+ case SyntaxKind.JSDocVariadicType:
3713
+ return getTypeFromJSDocType((<JSDocVariadicType>jsDocType).type);
3714
+ case SyntaxKind.JSDocConstructorType:
3715
+ // NYI:
3716
+ break;
3717
+ case SyntaxKind.JSDocThisType:
3718
+ // NYI:
3719
+ break;
3720
+ }
3721
+ }
3722
+ }
3723
+
3724
+ function getTypeForJSDocTypeReference(node: JSDocTypeReference): Type {
3725
+ if (node.name.kind === SyntaxKind.Identifier) {
3726
+ switch ((<Identifier>node.name).text) {
3727
+ case "any": return anyType;
3728
+ case "boolean": return booleanType;
3729
+ case "number": return numberType;
3730
+ case "string": return stringType;
3731
+ case "symbol": return esSymbolType;
3732
+ }
3733
+ }
3734
+
3735
+ let symbol = resolveEntityName(node.name, SymbolFlags.Type);
3736
+ if (symbol) {
3737
+ let type = getDeclaredTypeOfSymbol(symbol);
3738
+ if (type.flags & (TypeFlags.Class | TypeFlags.Interface) && type.flags & TypeFlags.Reference) {
3739
+ let typeParameters = (<InterfaceType>type).typeParameters;
3740
+ if (node.typeArguments && node.typeArguments.length === typeParameters.length) {
3741
+ let typeArguments = map(node.typeArguments, getTypeFromJSDocType);
3742
+ for (let typeArgument in typeArguments) {
3743
+ if (!typeArgument) {
3744
+ return undefined;
3745
+ }
3746
+ }
3747
+
3748
+ type = createTypeReference(<GenericType>type, typeArguments);
3749
+ }
3750
+ }
3751
+
3752
+ return type;
3753
+ }
3754
+
3755
+ return undefined;
3756
+ }
3757
+
3758
+ function getTypeFromJSDocUnionType(node: JSDocUnionType): Type {
3759
+ return getUnionType(map(node.types, getTypeFromJSDocType), /*noSubtypeReduction*/ true);
3760
+ }
3761
+
3621
3762
function getTypeFromTypeNodeOrHeritageClauseElement(node: TypeNode | LiteralExpression | HeritageClauseElement): Type {
3622
3763
switch (node.kind) {
3623
3764
case SyntaxKind.AnyKeyword:
0 commit comments