@@ -532,7 +532,7 @@ namespace ts {
532532 }
533533
534534 // Because of module/namespace merging, a module's exports are in scope,
535- // yet we never want to treat an export specifier as putting a member in scope.
535+ // yet we never want to treat an export specifier as putting a member in scope.
536536 // Therefore, if the name we find is purely an export specifier, it is not actually considered in scope.
537537 // Two things to note about this:
538538 // 1. We have to check this without calling getSymbol. The problem with calling getSymbol
@@ -1028,16 +1028,12 @@ namespace ts {
10281028
10291029 // Module names are escaped in our symbol table. However, string literal values aren't.
10301030 // Escape the name in the "require(...)" clause to ensure we find the right symbol.
1031- let moduleName = escapeIdentifier(moduleReferenceLiteral.text);
1031+ const moduleName = escapeIdentifier(moduleReferenceLiteral.text);
10321032
10331033 if (moduleName === undefined) {
10341034 return;
10351035 }
10361036
1037- if (moduleName.indexOf("!") >= 0) {
1038- moduleName = moduleName.substr(0, moduleName.indexOf("!"));
1039- }
1040-
10411037 const isRelative = isExternalModuleNameRelative(moduleName);
10421038 if (!isRelative) {
10431039 const symbol = getSymbol(globals, "\"" + moduleName + "\"", SymbolFlags.ValueModule);
@@ -3201,7 +3197,7 @@ namespace ts {
32013197 case SyntaxKind.BooleanKeyword:
32023198 case SyntaxKind.SymbolKeyword:
32033199 case SyntaxKind.VoidKeyword:
3204- case SyntaxKind.StringLiteral :
3200+ case SyntaxKind.StringLiteralType :
32053201 return true;
32063202 case SyntaxKind.ArrayType:
32073203 return isIndependentType((<ArrayTypeNode>node).elementType);
@@ -3862,7 +3858,7 @@ namespace ts {
38623858 paramSymbol = resolvedSymbol;
38633859 }
38643860 parameters.push(paramSymbol);
3865- if (param.type && param.type.kind === SyntaxKind.StringLiteral ) {
3861+ if (param.type && param.type.kind === SyntaxKind.StringLiteralType ) {
38663862 hasStringLiterals = true;
38673863 }
38683864
@@ -4531,8 +4527,7 @@ namespace ts {
45314527 return links.resolvedType;
45324528 }
45334529
4534- function getStringLiteralType(node: StringLiteral): StringLiteralType {
4535- const text = node.text;
4530+ function getStringLiteralType(text: string): StringLiteralType {
45364531 if (hasProperty(stringLiteralTypes, text)) {
45374532 return stringLiteralTypes[text];
45384533 }
@@ -4542,10 +4537,10 @@ namespace ts {
45424537 return type;
45434538 }
45444539
4545- function getTypeFromStringLiteral(node: StringLiteral): Type {
4540+ function getTypeFromStringLiteral(node: StringLiteral | StringLiteralTypeNode ): Type {
45464541 const links = getNodeLinks(node);
45474542 if (!links.resolvedType) {
4548- links.resolvedType = getStringLiteralType(node);
4543+ links.resolvedType = getStringLiteralType(node.text );
45494544 }
45504545 return links.resolvedType;
45514546 }
@@ -4587,8 +4582,8 @@ namespace ts {
45874582 return voidType;
45884583 case SyntaxKind.ThisType:
45894584 return getTypeFromThisTypeNode(node);
4590- case SyntaxKind.StringLiteral :
4591- return getTypeFromStringLiteral(<StringLiteral >node);
4585+ case SyntaxKind.StringLiteralType :
4586+ return getTypeFromStringLiteral(<StringLiteralTypeNode >node);
45924587 case SyntaxKind.TypeReference:
45934588 return getTypeFromTypeReference(<TypeReferenceNode>node);
45944589 case SyntaxKind.TypePredicate:
@@ -5228,9 +5223,12 @@ namespace ts {
52285223 const id = relation !== identityRelation || apparentSource.id < target.id ? apparentSource.id + "," + target.id : target.id + "," + apparentSource.id;
52295224 const related = relation[id];
52305225 if (related !== undefined) {
5231- // If we computed this relation already and it was failed and reported, or if we're not being asked to elaborate
5232- // errors, we can use the cached value. Otherwise, recompute the relation
5233- if (!elaborateErrors || (related === RelationComparisonResult.FailedAndReported)) {
5226+ if (elaborateErrors && related === RelationComparisonResult.Failed) {
5227+ // We are elaborating errors and the cached result is an unreported failure. Record the result as a reported
5228+ // failure and continue computing the relation such that errors get reported.
5229+ relation[id] = RelationComparisonResult.FailedAndReported;
5230+ }
5231+ else {
52345232 return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
52355233 }
52365234 }
@@ -6086,6 +6084,17 @@ namespace ts {
60866084 }
60876085
60886086 function inferFromTypes(source: Type, target: Type) {
6087+ if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union ||
6088+ source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) {
6089+ // Source and target are both unions or both intersections. To improve the quality of
6090+ // inferences we first reduce the types by removing constituents that are identically
6091+ // matched by a constituent in the other type. For example, when inferring from
6092+ // 'string | string[]' to 'string | T', we reduce the types to 'string[]' and 'T'.
6093+ const reducedSource = reduceUnionOrIntersectionType(<UnionOrIntersectionType>source, <UnionOrIntersectionType>target);
6094+ const reducedTarget = reduceUnionOrIntersectionType(<UnionOrIntersectionType>target, <UnionOrIntersectionType>source);
6095+ source = reducedSource;
6096+ target = reducedTarget;
6097+ }
60896098 if (target.flags & TypeFlags.TypeParameter) {
60906099 // If target is a type parameter, make an inference, unless the source type contains
60916100 // the anyFunctionType (the wildcard type that's used to avoid contextually typing functions).
@@ -6096,7 +6105,6 @@ namespace ts {
60966105 if (source.flags & TypeFlags.ContainsAnyFunctionType) {
60976106 return;
60986107 }
6099-
61006108 const typeParameters = context.typeParameters;
61016109 for (let i = 0; i < typeParameters.length; i++) {
61026110 if (target === typeParameters[i]) {
@@ -6244,6 +6252,41 @@ namespace ts {
62446252 }
62456253 }
62466254
6255+ function typeIdenticalToSomeType(source: Type, target: UnionOrIntersectionType): boolean {
6256+ for (const t of target.types) {
6257+ if (isTypeIdenticalTo(source, t)) {
6258+ return true;
6259+ }
6260+ }
6261+ return false;
6262+ }
6263+
6264+ /**
6265+ * Return the reduced form of the source type. This type is computed by by removing all source
6266+ * constituents that have an identical match in the target type.
6267+ */
6268+ function reduceUnionOrIntersectionType(source: UnionOrIntersectionType, target: UnionOrIntersectionType) {
6269+ let sourceTypes = source.types;
6270+ let sourceIndex = 0;
6271+ let modified = false;
6272+ while (sourceIndex < sourceTypes.length) {
6273+ if (typeIdenticalToSomeType(sourceTypes[sourceIndex], target)) {
6274+ if (!modified) {
6275+ sourceTypes = sourceTypes.slice(0);
6276+ modified = true;
6277+ }
6278+ sourceTypes.splice(sourceIndex, 1);
6279+ }
6280+ else {
6281+ sourceIndex++;
6282+ }
6283+ }
6284+ if (modified) {
6285+ return source.flags & TypeFlags.Union ? getUnionType(sourceTypes, /*noSubtypeReduction*/ true) : getIntersectionType(sourceTypes);
6286+ }
6287+ return source;
6288+ }
6289+
62476290 function getInferenceCandidates(context: InferenceContext, index: number): Type[] {
62486291 const inferences = context.inferences[index];
62496292 return inferences.primary || inferences.secondary || emptyArray;
@@ -8747,7 +8790,7 @@ namespace ts {
87478790 // for the argument. In that case, we should check the argument.
87488791 if (argType === undefined) {
87498792 argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors
8750- ? getStringLiteralType(<StringLiteral>arg)
8793+ ? getStringLiteralType(( <StringLiteral>arg).text )
87518794 : checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
87528795 }
87538796
@@ -8942,7 +8985,7 @@ namespace ts {
89428985 case SyntaxKind.Identifier:
89438986 case SyntaxKind.NumericLiteral:
89448987 case SyntaxKind.StringLiteral:
8945- return getStringLiteralType(<StringLiteral >element.name);
8988+ return getStringLiteralType((<Identifier | LiteralExpression >element.name).text );
89468989
89478990 case SyntaxKind.ComputedPropertyName:
89488991 const nameType = checkComputedPropertyName(<ComputedPropertyName>element.name);
@@ -10564,7 +10607,8 @@ namespace ts {
1056410607 function checkStringLiteralExpression(node: StringLiteral): Type {
1056510608 const contextualType = getContextualType(node);
1056610609 if (contextualType && contextualTypeIsStringLiteralType(contextualType)) {
10567- return getStringLiteralType(node);
10610+ // TODO (drosen): Consider using getTypeFromStringLiteral instead
10611+ return getStringLiteralType(node.text);
1056810612 }
1056910613
1057010614 return stringType;
@@ -11398,7 +11442,7 @@ namespace ts {
1139811442 // we can get here in two cases
1139911443 // 1. mixed static and instance class members
1140011444 // 2. something with the same name was defined before the set of overloads that prevents them from merging
11401- // here we'll report error only for the first case since for second we should already report error in binder
11445+ // here we'll report error only for the first case since for second we should already report error in binder
1140211446 if (reportError) {
1140311447 const diagnostic = node.flags & NodeFlags.Static ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static;
1140411448 error(errorNode, diagnostic);
0 commit comments