Skip to content

Commit d415b57

Browse files
committed
Merge branch 'master' into falseAssertions
2 parents feed4b9 + afe6f4c commit d415b57

25 files changed

+12327
-11904
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ with any additional questions or comments.
4242

4343
## Documentation
4444

45-
* [Quick tutorial](https://www.typescriptlang.org/docs/tutorial.html)
45+
* [TypeScript in 5 minutes](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html)
4646
* [Programming handbook](https://www.typescriptlang.org/docs/handbook/basic-types.html)
4747
* [Language specification](https://github.com/microsoft/TypeScript/blob/master/doc/spec.md)
4848
* [Homepage](https://www.typescriptlang.org/)

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@
5454
"@types/through2": "latest",
5555
"@types/travis-fold": "latest",
5656
"@types/xml2js": "^0.4.0",
57-
"@typescript-eslint/eslint-plugin": "2.2.0",
58-
"@typescript-eslint/experimental-utils": "2.2.0",
59-
"@typescript-eslint/parser": "2.2.0",
57+
"@typescript-eslint/eslint-plugin": "2.3.2",
58+
"@typescript-eslint/experimental-utils": "2.3.2",
59+
"@typescript-eslint/parser": "2.3.2",
6060
"async": "latest",
6161
"azure-devops-node-api": "^8.0.0",
6262
"browser-resolve": "^1.11.2",
@@ -65,10 +65,10 @@
6565
"chalk": "latest",
6666
"convert-source-map": "latest",
6767
"del": "5.1.0",
68-
"eslint": "6.3.0",
68+
"eslint": "6.5.1",
6969
"eslint-formatter-autolinkable-stylish": "1.0.3",
7070
"eslint-plugin-import": "2.18.2",
71-
"eslint-plugin-jsdoc": "15.9.1",
71+
"eslint-plugin-jsdoc": "15.9.9",
7272
"eslint-plugin-no-null": "1.0.2",
7373
"fancy-log": "latest",
7474
"fs-extra": "^6.0.1",

src/compiler/binder.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -856,9 +856,8 @@ namespace ts {
856856
function isNarrowableReference(expr: Expression): boolean {
857857
return expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.ThisKeyword || expr.kind === SyntaxKind.SuperKeyword ||
858858
(isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression) ||
859-
isElementAccessExpression(expr) &&
860-
isStringOrNumericLiteralLike(expr.argumentExpression) &&
861-
isNarrowableReference(expr.expression);
859+
isElementAccessExpression(expr) && isStringOrNumericLiteralLike(expr.argumentExpression) && isNarrowableReference(expr.expression) ||
860+
isOptionalChain(expr);
862861
}
863862

864863
function hasNarrowableArgument(expr: CallExpression) {

src/compiler/checker.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18124,6 +18124,16 @@ namespace ts {
1812418124
return false;
1812518125
}
1812618126

18127+
function optionalChainContainsReference(source: Node, target: Node) {
18128+
while (isOptionalChain(source)) {
18129+
source = source.expression;
18130+
if (isMatchingReference(source, target)) {
18131+
return true;
18132+
}
18133+
}
18134+
return false;
18135+
}
18136+
1812718137
// Return true if target is a property access xxx.yyy, source is a property access xxx.zzz, the declared
1812818138
// type of xxx is a union type, and yyy is a property that is possibly a discriminant. We consider a property
1812918139
// a possible discriminant if its type differs in the constituents of containing union type, and if every
@@ -19378,6 +19388,14 @@ namespace ts {
1937819388
if (isMatchingReference(reference, right)) {
1937919389
return narrowTypeByEquality(type, operator, left, assumeTrue);
1938019390
}
19391+
if (assumeTrue && strictNullChecks) {
19392+
if (optionalChainContainsReference(left, reference)) {
19393+
type = narrowTypeByOptionalChainContainment(type, operator, right);
19394+
}
19395+
else if (optionalChainContainsReference(right, reference)) {
19396+
type = narrowTypeByOptionalChainContainment(type, operator, left);
19397+
}
19398+
}
1938119399
if (isMatchingReferenceDiscriminant(left, declaredType)) {
1938219400
return narrowTypeByDiscriminant(type, <AccessExpression>left, t => narrowTypeByEquality(t, operator, right, assumeTrue));
1938319401
}
@@ -19402,6 +19420,18 @@ namespace ts {
1940219420
return type;
1940319421
}
1940419422

19423+
function narrowTypeByOptionalChainContainment(type: Type, operator: SyntaxKind, value: Expression): Type {
19424+
// We are in the true branch of obj?.foo === value or obj?.foo !== value. We remove undefined and null from
19425+
// the type of obj if (a) the operator is === and the type of value doesn't include undefined or (b) the
19426+
// operator is !== and the type of value is undefined.
19427+
const valueType = getTypeOfExpression(value);
19428+
return operator === SyntaxKind.EqualsEqualsToken && !(getTypeFacts(valueType) & TypeFacts.EQUndefinedOrNull) ||
19429+
operator === SyntaxKind.EqualsEqualsEqualsToken && !(getTypeFacts(valueType) & TypeFacts.EQUndefined) ||
19430+
operator === SyntaxKind.ExclamationEqualsToken && valueType.flags & TypeFlags.Nullable ||
19431+
operator === SyntaxKind.ExclamationEqualsEqualsToken && valueType.flags & TypeFlags.Undefined ?
19432+
getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type;
19433+
}
19434+
1940519435
function narrowTypeByEquality(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type {
1940619436
if (type.flags & TypeFlags.Any) {
1940719437
return type;
@@ -19452,6 +19482,10 @@ namespace ts {
1945219482
// We have '==', '!=', '===', or !==' operator with 'typeof xxx' and string literal operands
1945319483
const target = getReferenceCandidate(typeOfExpr.expression);
1945419484
if (!isMatchingReference(reference, target)) {
19485+
if (assumeTrue && (operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken) &&
19486+
strictNullChecks && optionalChainContainsReference(target, reference)) {
19487+
return getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull);
19488+
}
1945519489
// For a reference of the form 'x.y', a 'typeof x === ...' type guard resets the
1945619490
// narrowed type of 'y' to its declared type.
1945719491
if (containsMatchingReference(reference, target)) {
@@ -19633,6 +19667,9 @@ namespace ts {
1963319667
function narrowTypeByInstanceof(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
1963419668
const left = getReferenceCandidate(expr.left);
1963519669
if (!isMatchingReference(reference, left)) {
19670+
if (assumeTrue && strictNullChecks && optionalChainContainsReference(left, reference)) {
19671+
return getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull);
19672+
}
1963619673
// For a reference of the form 'x.y', an 'x instanceof T' type guard resets the
1963719674
// narrowed type of 'y' to its declared type. We do this because preceding 'x.y'
1963819675
// references might reference a different 'y' property. However, we make an exception
@@ -23621,7 +23658,20 @@ namespace ts {
2362123658
// If the signature's 'this' type is voidType, then the check is skipped -- anything is compatible.
2362223659
// If the expression is a new expression, then the check is skipped.
2362323660
const thisArgumentNode = getThisArgumentOfCall(node);
23624-
const thisArgumentType = thisArgumentNode ? checkExpression(thisArgumentNode) : voidType;
23661+
let thisArgumentType: Type;
23662+
if (thisArgumentNode) {
23663+
thisArgumentType = checkExpression(thisArgumentNode);
23664+
if (isOptionalChainRoot(thisArgumentNode.parent)) {
23665+
thisArgumentType = getNonNullableType(thisArgumentType);
23666+
}
23667+
else if (isOptionalChain(thisArgumentNode.parent)) {
23668+
thisArgumentType = removeOptionalTypeMarker(thisArgumentType);
23669+
}
23670+
}
23671+
else {
23672+
thisArgumentType = voidType;
23673+
}
23674+
2362523675
const errorNode = reportErrors ? (thisArgumentNode || node) : undefined;
2362623676
const headMessage = Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1;
2362723677
if (!checkTypeRelatedTo(thisArgumentType, thisType, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer)) {

src/compiler/utilities.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,9 +2174,11 @@ namespace ts {
21742174
nextToLast = nextToLast.expression as Exclude<BindableStaticNameExpression, Identifier>;
21752175
}
21762176
const id = nextToLast.expression;
2177-
if (id.escapedText === "exports" ||
2178-
id.escapedText === "module" && getElementOrPropertyAccessName(nextToLast) === "exports") {
2179-
// exports.name = expr OR module.exports.name = expr
2177+
if ((id.escapedText === "exports" ||
2178+
id.escapedText === "module" && getElementOrPropertyAccessName(nextToLast) === "exports") &&
2179+
// ExportsProperty does not support binding with computed names
2180+
isBindableStaticAccessExpression(lhs)) {
2181+
// exports.name = expr OR module.exports.name = expr OR exports["name"] = expr ...
21802182
return AssignmentDeclarationKind.ExportsProperty;
21812183
}
21822184
// F.G...x = expr

0 commit comments

Comments
 (0)