@@ -251,6 +251,7 @@ namespace ts {
251251 getSuggestionForNonexistentProperty: (node, type) => getSuggestionForNonexistentProperty(node, type),
252252 getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning),
253253 getBaseConstraintOfType,
254+ getDefaultFromTypeParameter: type => type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) : undefined,
254255 resolveName(name, location, meaning) {
255256 return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false);
256257 },
@@ -4054,25 +4055,30 @@ namespace ts {
40544055 }
40554056 }
40564057
4057- function collectLinkedAliases(node: Identifier): Node[] {
4058+ function collectLinkedAliases(node: Identifier, setVisibility?: boolean ): Node[] | undefined {
40584059 let exportSymbol: Symbol;
40594060 if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) {
4060- exportSymbol = resolveName(node.parent , node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, Diagnostics.Cannot_find_name_0 , node, /*isUse*/ false);
4061+ exportSymbol = resolveName(node, node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined , node, /*isUse*/ false);
40614062 }
40624063 else if (node.parent.kind === SyntaxKind.ExportSpecifier) {
40634064 exportSymbol = getTargetOfExportSpecifier(<ExportSpecifier>node.parent, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias);
40644065 }
4065- const result: Node[] = [];
4066+ let result: Node[];
40664067 if (exportSymbol) {
40674068 buildVisibleNodeList(exportSymbol.declarations);
40684069 }
40694070 return result;
40704071
40714072 function buildVisibleNodeList(declarations: Declaration[]) {
40724073 forEach(declarations, declaration => {
4073- getNodeLinks(declaration).isVisible = true;
40744074 const resultNode = getAnyImportSyntax(declaration) || declaration;
4075- pushIfUnique(result, resultNode);
4075+ if (setVisibility) {
4076+ getNodeLinks(declaration).isVisible = true;
4077+ }
4078+ else {
4079+ result = result || [];
4080+ pushIfUnique(result, resultNode);
4081+ }
40764082
40774083 if (isInternalModuleImportEqualsDeclaration(declaration)) {
40784084 // Add the referenced top container visible
@@ -4231,7 +4237,7 @@ namespace ts {
42314237 /** Return the inferred type for a binding element */
42324238 function getTypeForBindingElement(declaration: BindingElement): Type {
42334239 const pattern = declaration.parent;
4234- const parentType = getTypeForBindingElementParent(pattern.parent);
4240+ let parentType = getTypeForBindingElementParent(pattern.parent);
42354241 // If parent has the unknown (error) type, then so does this binding element
42364242 if (parentType === unknownType) {
42374243 return unknownType;
@@ -4273,6 +4279,10 @@ namespace ts {
42734279 // or otherwise the type of the string index signature.
42744280 const text = getTextOfPropertyName(name);
42754281
4282+ // Relax null check on ambient destructuring parameters, since the parameters have no implementation and are just documentation
4283+ if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isParameterDeclaration(declaration)) {
4284+ parentType = getNonNullableType(parentType);
4285+ }
42764286 const declaredType = getTypeOfPropertyOfType(parentType, text);
42774287 type = declaredType && getFlowTypeOfReference(declaration, declaredType) ||
42784288 isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
@@ -15746,61 +15756,95 @@ namespace ts {
1574615756 * except for candidates:
1574715757 * * With no name
1574815758 * * Whose meaning doesn't match the `meaning` parameter.
15749- * * Whose length differs from the target name by more than 0.3 of the length of the name.
15759+ * * Whose length differs from the target name by more than 0.34 of the length of the name.
1575015760 * * Whose levenshtein distance is more than 0.4 of the length of the name
1575115761 * (0.4 allows 1 substitution/transposition for every 5 characters,
1575215762 * and 1 insertion/deletion at 3 characters)
15753- * Names longer than 30 characters don't get suggestions because Levenshtein distance is an n**2 algorithm.
1575415763 */
1575515764 function getSpellingSuggestionForName(name: string, symbols: Symbol[], meaning: SymbolFlags): Symbol | undefined {
15756- const worstDistance = name.length * 0.4;
15757- const maximumLengthDifference = Math.min(3, name.length * 0.34);
15758- let bestDistance = Number.MAX_VALUE;
15759- let bestCandidate = undefined;
15765+ const maximumLengthDifference = Math.min(2, Math.floor(name.length * 0.34));
15766+ let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result isn't better than this, don't bother.
15767+ let bestCandidate: Symbol | undefined;
1576015768 let justCheckExactMatches = false;
15761- if (name.length > 30) {
15762- return undefined;
15763- }
15764- name = name.toLowerCase();
15769+ const nameLowerCase = name.toLowerCase();
1576515770 for (const candidate of symbols) {
15766- let candidateName = symbolName(candidate);
15767- if (candidate.flags & meaning &&
15768- candidateName &&
15769- Math.abs(candidateName.length - name.length) < maximumLengthDifference) {
15770- candidateName = candidateName.toLowerCase();
15771- if (candidateName === name) {
15772- return candidate;
15773- }
15774- if (justCheckExactMatches) {
15775- continue;
15776- }
15777- if (candidateName.length < 3 ||
15778- name.length < 3 ||
15779- candidateName === "eval" ||
15780- candidateName === "intl" ||
15781- candidateName === "undefined" ||
15782- candidateName === "map" ||
15783- candidateName === "nan" ||
15784- candidateName === "set") {
15785- continue;
15786- }
15787- const distance = levenshtein(name, candidateName);
15788- if (distance > worstDistance) {
15789- continue;
15790- }
15791- if (distance < 3) {
15792- justCheckExactMatches = true;
15793- bestCandidate = candidate;
15794- }
15795- else if (distance < bestDistance) {
15796- bestDistance = distance;
15797- bestCandidate = candidate;
15798- }
15771+ const candidateName = symbolName(candidate);
15772+ if (!(candidate.flags & meaning && Math.abs(candidateName.length - nameLowerCase.length) <= maximumLengthDifference)) {
15773+ continue;
15774+ }
15775+ const candidateNameLowerCase = candidateName.toLowerCase();
15776+ if (candidateNameLowerCase === nameLowerCase) {
15777+ return candidate;
15778+ }
15779+ if (justCheckExactMatches) {
15780+ continue;
15781+ }
15782+ if (candidateName.length < 3) {
15783+ // Don't bother, user would have noticed a 2-character name having an extra character
15784+ continue;
15785+ }
15786+ // Only care about a result better than the best so far.
15787+ const distance = levenshteinWithMax(nameLowerCase, candidateNameLowerCase, bestDistance - 1);
15788+ if (distance === undefined) {
15789+ continue;
15790+ }
15791+ if (distance < 3) {
15792+ justCheckExactMatches = true;
15793+ bestCandidate = candidate;
15794+ }
15795+ else {
15796+ Debug.assert(distance < bestDistance); // Else `levenshteinWithMax` should return undefined
15797+ bestDistance = distance;
15798+ bestCandidate = candidate;
1579915799 }
1580015800 }
1580115801 return bestCandidate;
1580215802 }
1580315803
15804+ function levenshteinWithMax(s1: string, s2: string, max: number): number | undefined {
15805+ let previous = new Array(s2.length + 1);
15806+ let current = new Array(s2.length + 1);
15807+ /** Represents any value > max. We don't care about the particular value. */
15808+ const big = max + 1;
15809+
15810+ for (let i = 0; i <= s2.length; i++) {
15811+ previous[i] = i;
15812+ }
15813+
15814+ for (let i = 1; i <= s1.length; i++) {
15815+ const c1 = s1.charCodeAt(i - 1);
15816+ const minJ = i > max ? i - max : 1;
15817+ const maxJ = s2.length > max + i ? max + i : s2.length;
15818+ current[0] = i;
15819+ /** Smallest value of the matrix in the ith column. */
15820+ let colMin = i;
15821+ for (let j = 1; j < minJ; j++) {
15822+ current[j] = big;
15823+ }
15824+ for (let j = minJ; j <= maxJ; j++) {
15825+ const dist = c1 === s2.charCodeAt(j - 1)
15826+ ? previous[j - 1]
15827+ : Math.min(/*delete*/ previous[j] + 1, /*insert*/ current[j - 1] + 1, /*substitute*/ previous[j - 1] + 2);
15828+ current[j] = dist;
15829+ colMin = Math.min(colMin, dist);
15830+ }
15831+ for (let j = maxJ + 1; j <= s2.length; j++) {
15832+ current[j] = big;
15833+ }
15834+ if (colMin > max) {
15835+ // Give up -- everything in this column is > max and it can't get better in future columns.
15836+ return undefined;
15837+ }
15838+
15839+ const temp = previous;
15840+ previous = current;
15841+ current = temp;
15842+ }
15843+
15844+ const res = previous[s2.length];
15845+ return res > max ? undefined : res;
15846+ }
15847+
1580415848 function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isThisAccess: boolean) {
1580515849 if (prop &&
1580615850 noUnusedIdentifiers &&
@@ -23335,6 +23379,9 @@ namespace ts {
2333523379
2333623380 function checkExportSpecifier(node: ExportSpecifier) {
2333723381 checkAliasSymbol(node);
23382+ if (compilerOptions.declaration) {
23383+ collectLinkedAliases(node.propertyName || node.name, /*setVisibility*/ true);
23384+ }
2333823385 if (!(<ExportDeclaration>node.parent.parent).moduleSpecifier) {
2333923386 const exportedName = node.propertyName || node.name;
2334023387 // find immediate value referenced by exported name (SymbolFlags.Alias is set so we don't chase down aliases)
@@ -23372,6 +23419,10 @@ namespace ts {
2337223419 }
2337323420 if (node.expression.kind === SyntaxKind.Identifier) {
2337423421 markExportAsReferenced(node);
23422+
23423+ if (compilerOptions.declaration) {
23424+ collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true);
23425+ }
2337523426 }
2337623427 else {
2337723428 checkExpressionCached(node.expression);
@@ -26243,14 +26294,17 @@ namespace ts {
2624326294 }
2624426295
2624526296 function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) {
26246- if (node.typeParameters) {
26247- return grammarErrorAtPos(node, node.typeParameters.pos, node.typeParameters.end - node.typeParameters.pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
26297+ const typeParameters = getEffectiveTypeParameterDeclarations(node);
26298+ if (typeParameters) {
26299+ const { pos, end } = isNodeArray(typeParameters) ? typeParameters : first(typeParameters);
26300+ return grammarErrorAtPos(node, pos, end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
2624826301 }
2624926302 }
2625026303
2625126304 function checkGrammarConstructorTypeAnnotation(node: ConstructorDeclaration) {
26252- if (node.type) {
26253- return grammarErrorOnNode(node.type, Diagnostics.Type_annotation_cannot_appear_on_a_constructor_declaration);
26305+ const type = getEffectiveReturnTypeNode(node);
26306+ if (type) {
26307+ return grammarErrorOnNode(type, Diagnostics.Type_annotation_cannot_appear_on_a_constructor_declaration);
2625426308 }
2625526309 }
2625626310
0 commit comments