Add support for Optional Chaining (#33294)

* Add support for Optional Chaining

* Add grammar error for invalid tagged template, more tests

* Prototype

* PR feedback

* Add errors for invalid assignments and a trailing '?.'

* Add additional signature help test, fix lint warnings

* Fix to insert text for completions

* Add initial control-flow analysis for optional chains

* PR Feedback and more tests

* Update to control flow

* Remove mangled smart quotes in comments

* Fix lint, PR feedback

* Updates to control flow

* Switch to FlowCondition for CFA of optional chains

* Fix ?. insertion for completions on type variables

* Accept API baseline change

* Clean up types

* improve control-flow debug output

* Revert Debug.formatControlFlowGraph helper
This commit is contained in:
Ron Buckton
2019-09-30 12:33:28 -07:00
committed by GitHub
parent 7ce793c5b8
commit fcd9334f57
76 changed files with 6422 additions and 885 deletions
+121 -24
View File
@@ -797,6 +797,10 @@ namespace ts {
case SyntaxKind.VariableDeclaration:
bindVariableDeclarationFlow(<VariableDeclaration>node);
break;
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
bindAccessExpressionFlow(<AccessExpression>node);
break;
case SyntaxKind.CallExpression:
bindCallExpressionFlow(<CallExpression>node);
break;
@@ -941,7 +945,9 @@ namespace ts {
}
if (expression.kind === SyntaxKind.TrueKeyword && flags & FlowFlags.FalseCondition ||
expression.kind === SyntaxKind.FalseKeyword && flags & FlowFlags.TrueCondition) {
return unreachableFlow;
if (!isOptionalChainRoot(expression.parent)) {
return unreachableFlow;
}
}
if (!isNarrowingExpression(expression)) {
return antecedent;
@@ -1015,23 +1021,28 @@ namespace ts {
}
function isTopLevelLogicalExpression(node: Node): boolean {
while (node.parent.kind === SyntaxKind.ParenthesizedExpression ||
node.parent.kind === SyntaxKind.PrefixUnaryExpression &&
(<PrefixUnaryExpression>node.parent).operator === SyntaxKind.ExclamationToken) {
while (isParenthesizedExpression(node.parent) ||
isPrefixUnaryExpression(node.parent) && node.parent.operator === SyntaxKind.ExclamationToken) {
node = node.parent;
}
return !isStatementCondition(node) && !isLogicalExpression(node.parent);
return !isStatementCondition(node) &&
!isLogicalExpression(node.parent) &&
!(isOptionalChain(node.parent) && node.parent.expression === node);
}
function doWithConditionalBranches<T>(action: (value: T) => void, value: T, trueTarget: FlowLabel, falseTarget: FlowLabel) {
const savedTrueTarget = currentTrueTarget;
const savedFalseTarget = currentFalseTarget;
currentTrueTarget = trueTarget;
currentFalseTarget = falseTarget;
action(value);
currentTrueTarget = savedTrueTarget;
currentFalseTarget = savedFalseTarget;
}
function bindCondition(node: Expression | undefined, trueTarget: FlowLabel, falseTarget: FlowLabel) {
const saveTrueTarget = currentTrueTarget;
const saveFalseTarget = currentFalseTarget;
currentTrueTarget = trueTarget;
currentFalseTarget = falseTarget;
bind(node);
currentTrueTarget = saveTrueTarget;
currentFalseTarget = saveFalseTarget;
if (!node || !isLogicalExpression(node)) {
doWithConditionalBranches(bind, node, trueTarget, falseTarget);
if (!node || !isLogicalExpression(node) && !(isOptionalChain(node) && isOutermostOptionalChain(node))) {
addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node));
addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node));
}
@@ -1536,22 +1547,96 @@ namespace ts {
}
}
function bindCallExpressionFlow(node: CallExpression) {
// If the target of the call expression is a function expression or arrow function we have
// an immediately invoked function expression (IIFE). Initialize the flowNode property to
// the current control flow (which includes evaluation of the IIFE arguments).
let expr: Expression = node.expression;
while (expr.kind === SyntaxKind.ParenthesizedExpression) {
expr = (<ParenthesizedExpression>expr).expression;
function isOutermostOptionalChain(node: OptionalChain) {
return !isOptionalChain(node.parent) || isOptionalChainRoot(node.parent) || node !== node.parent.expression;
}
function bindOptionalExpression(node: Expression, trueTarget: FlowLabel, falseTarget: FlowLabel) {
doWithConditionalBranches(bind, node, trueTarget, falseTarget);
if (!isOptionalChain(node) || isOutermostOptionalChain(node)) {
addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node));
addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node));
}
if (expr.kind === SyntaxKind.FunctionExpression || expr.kind === SyntaxKind.ArrowFunction) {
bindEach(node.typeArguments);
bindEach(node.arguments);
bind(node.expression);
}
function bindOptionalChainRest(node: OptionalChain) {
bind(node.questionDotToken);
switch (node.kind) {
case SyntaxKind.PropertyAccessExpression:
bind(node.name);
break;
case SyntaxKind.ElementAccessExpression:
bind(node.argumentExpression);
break;
case SyntaxKind.CallExpression:
bindEach(node.typeArguments);
bindEach(node.arguments);
break;
}
}
function bindOptionalChain(node: OptionalChain, trueTarget: FlowLabel, falseTarget: FlowLabel) {
// For an optional chain, we emulate the behavior of a logical expression:
//
// a?.b -> a && a.b
// a?.b.c -> a && a.b.c
// a?.b?.c -> a && a.b && a.b.c
// a?.[x = 1] -> a && a[x = 1]
//
// To do this we descend through the chain until we reach the root of a chain (the expression with a `?.`)
// and build it's CFA graph as if it were the first condition (`a && ...`). Then we bind the rest
// of the node as part of the "true" branch, and continue to do so as we ascend back up to the outermost
// chain node. We then treat the entire node as the right side of the expression.
const preChainLabel = node.questionDotToken ? createBranchLabel() : undefined;
bindOptionalExpression(node.expression, preChainLabel || trueTarget, falseTarget);
if (preChainLabel) {
currentFlow = finishFlowLabel(preChainLabel);
}
doWithConditionalBranches(bindOptionalChainRest, node, trueTarget, falseTarget);
if (isOutermostOptionalChain(node)) {
addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node));
addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node));
}
}
function bindOptionalChainFlow(node: OptionalChain) {
if (isTopLevelLogicalExpression(node)) {
const postExpressionLabel = createBranchLabel();
bindOptionalChain(node, postExpressionLabel, postExpressionLabel);
currentFlow = finishFlowLabel(postExpressionLabel);
}
else {
bindOptionalChain(node, currentTrueTarget!, currentFalseTarget!);
}
}
function bindAccessExpressionFlow(node: AccessExpression) {
if (isOptionalChain(node)) {
bindOptionalChainFlow(node);
}
else {
bindEachChild(node);
}
}
function bindCallExpressionFlow(node: CallExpression) {
if (isOptionalChain(node)) {
bindOptionalChainFlow(node);
}
else {
// If the target of the call expression is a function expression or arrow function we have
// an immediately invoked function expression (IIFE). Initialize the flowNode property to
// the current control flow (which includes evaluation of the IIFE arguments).
const expr = skipParentheses(node.expression);
if (expr.kind === SyntaxKind.FunctionExpression || expr.kind === SyntaxKind.ArrowFunction) {
bindEach(node.typeArguments);
bindEach(node.arguments);
bind(node.expression);
}
else {
bindEachChild(node);
}
}
if (node.expression.kind === SyntaxKind.PropertyAccessExpression) {
const propertyAccess = <PropertyAccessExpression>node.expression;
if (isNarrowableOperand(propertyAccess.expression) && isPushOrUnshiftIdentifier(propertyAccess.name)) {
@@ -3297,6 +3382,10 @@ namespace ts {
const callee = skipOuterExpressions(node.expression);
const expression = node.expression;
if (node.flags & NodeFlags.OptionalChain) {
transformFlags |= TransformFlags.ContainsESNext;
}
if (node.typeArguments) {
transformFlags |= TransformFlags.AssertTypeScript;
}
@@ -3692,6 +3781,10 @@ namespace ts {
function computePropertyAccess(node: PropertyAccessExpression, subtreeFlags: TransformFlags) {
let transformFlags = subtreeFlags;
if (node.flags & NodeFlags.OptionalChain) {
transformFlags |= TransformFlags.ContainsESNext;
}
// If a PropertyAccessExpression starts with a super keyword, then it is
// ES6 syntax, and requires a lexical `this` binding.
if (node.expression.kind === SyntaxKind.SuperKeyword) {
@@ -3707,6 +3800,10 @@ namespace ts {
function computeElementAccess(node: ElementAccessExpression, subtreeFlags: TransformFlags) {
let transformFlags = subtreeFlags;
if (node.flags & NodeFlags.OptionalChain) {
transformFlags |= TransformFlags.ContainsESNext;
}
// If an ElementAccessExpression starts with a super keyword, then it is
// ES6 syntax, and requires a lexical `this` binding.
if (node.expression.kind === SyntaxKind.SuperKeyword) {
+159 -46
View File
@@ -333,6 +333,10 @@ namespace ts {
/** This will be set during calls to `getResolvedSignature` where services determines an apparent number of arguments greater than what is actually provided. */
let apparentArgumentCount: number | undefined;
// This object is reused for `checkOptionalExpression` return values to avoid frequent GC due to nursery object allocations.
// This object represents a pool-size of 1.
const pooledOptionalTypeResult: { isOptional: boolean, type: Type } = { isOptional: false, type: undefined! };
// for public members that accept a Node or one of its subtypes, we must guard against
// synthetic nodes created during transformations by calling `getParseTreeNode`.
// for most of these, we perform the guard only on `checker` to avoid any possible
@@ -380,8 +384,10 @@ namespace ts {
getParameterType: getTypeAtPosition,
getPromisedTypeOfPromise,
getReturnTypeOfSignature,
isNullableType,
getNullableType,
getNonNullableType,
getNonOptionalType: removeOptionalTypeMarker,
getTypeArguments,
typeToTypeNode: nodeBuilder.typeToTypeNode,
indexInfoToIndexSignatureDeclaration: nodeBuilder.indexInfoToIndexSignatureDeclaration,
@@ -546,6 +552,7 @@ namespace ts {
getNullType: () => nullType,
getESSymbolType: () => esSymbolType,
getNeverType: () => neverType,
getOptionalType: () => optionalType,
isSymbolAccessible,
getObjectFlags,
isArrayType,
@@ -648,6 +655,7 @@ namespace ts {
const unknownType = createIntrinsicType(TypeFlags.Unknown, "unknown");
const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined, "undefined", ObjectFlags.ContainsWideningType);
const optionalType = createIntrinsicType(TypeFlags.Undefined, "undefined");
const nullType = createIntrinsicType(TypeFlags.Null, "null");
const nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null, "null", ObjectFlags.ContainsWideningType);
const stringType = createIntrinsicType(TypeFlags.String, "string");
@@ -1171,7 +1179,7 @@ namespace ts {
// obtain item referenced by 'export='
mainModule = resolveExternalModuleSymbol(mainModule);
if (mainModule.flags & SymbolFlags.Namespace) {
// If we’re merging an augmentation to a pattern ambient module, we want to
// If we're merging an augmentation to a pattern ambient module, we want to
// perform the merge unidirectionally from the augmentation ('a.foo') to
// the pattern ('*.foo'), so that 'getMergedSymbol()' on a.foo gives you
// all the exports both from the pattern and from the augmentation, but
@@ -2657,7 +2665,7 @@ namespace ts {
if (patternAmbientModules) {
const pattern = findBestPatternMatch(patternAmbientModules, _ => _.pattern, moduleReference);
if (pattern) {
// If the module reference matched a pattern ambient module ('*.foo') but there’s also a
// If the module reference matched a pattern ambient module ('*.foo') but there's also a
// module augmentation by the specific name requested ('a.foo'), we store the merged symbol
// by the augmentation name ('a.foo'), because asking for *.foo should not give you exports
// from a.foo.
@@ -8599,6 +8607,12 @@ namespace ts {
return result;
}
function createOptionalCallSignature(signature: Signature) {
const result = cloneSignature(signature);
result.isOptionalCall = true;
return result;
}
function getExpandedParameters(sig: Signature): readonly Symbol[] {
if (sig.hasRestParameter) {
const restIndex = sig.parameters.length - 1;
@@ -10211,6 +10225,9 @@ namespace ts {
signature.unionSignatures ? getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype) :
getReturnTypeFromAnnotation(signature.declaration!) ||
(nodeIsMissing((<FunctionLikeDeclaration>signature.declaration).body) ? anyType : getReturnTypeFromBody(<FunctionLikeDeclaration>signature.declaration));
if (signature.isOptionalCall) {
type = propagateOptionalTypeMarker(type, /*wasOptional*/ true);
}
if (!popTypeResolution()) {
if (signature.declaration) {
const typeNode = getEffectiveReturnTypeNode(signature.declaration);
@@ -15653,7 +15670,7 @@ namespace ts {
for (const sourceProp of excludeProperties(getPropertiesOfType(source), excludedProperties)) {
if (!getPropertyOfObjectType(target, sourceProp.escapedName)) {
const sourceType = getTypeOfSymbol(sourceProp);
if (!(sourceType === undefinedType || sourceType === undefinedWideningType)) {
if (!(sourceType === undefinedType || sourceType === undefinedWideningType || sourceType === optionalType)) {
if (reportErrors) {
reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(sourceProp), typeToString(target));
}
@@ -16620,6 +16637,53 @@ namespace ts {
return strictNullChecks ? getGlobalNonNullableTypeInstantiation(type) : type;
}
function addOptionalTypeMarker(type: Type) {
return strictNullChecks ? getUnionType([type, optionalType]) : type;
}
function removeOptionalTypeMarker(type: Type): Type {
return strictNullChecks ? filterType(type, t => t !== optionalType) : type;
}
function propagateOptionalTypeMarker(type: Type, wasOptional: boolean) {
return wasOptional ? addOptionalTypeMarker(type) : type;
}
function createPooledOptionalTypeResult(isOptional: boolean, type: Type) {
pooledOptionalTypeResult.isOptional = isOptional;
pooledOptionalTypeResult.type = type;
return pooledOptionalTypeResult;
}
function checkOptionalExpression(
parent: PropertyAccessExpression | QualifiedName | ElementAccessExpression | CallExpression,
expression: Expression | QualifiedName,
nullDiagnostic?: DiagnosticMessage,
undefinedDiagnostic?: DiagnosticMessage,
nullOrUndefinedDiagnostic?: DiagnosticMessage,
) {
let isOptional = false;
let type = checkExpression(expression);
if (isOptionalChain(parent)) {
if (parent.questionDotToken) {
// If we have a questionDotToken then we are an OptionalExpression and should remove `null` and
// `undefined` from the type and add the optionalType to the result, if needed.
isOptional = isNullableType(type);
return createPooledOptionalTypeResult(isOptional, isOptional ? getNonNullableType(type) : type);
}
// If we do not have a questionDotToken, then we are an OptionalChain and we remove the optionalType and
// indicate whether we need to add optionalType back into the result.
const nonOptionalType = removeOptionalTypeMarker(type);
if (nonOptionalType !== type) {
isOptional = true;
type = nonOptionalType;
}
}
type = checkNonNullType(type, expression, nullDiagnostic, undefinedDiagnostic, nullOrUndefinedDiagnostic);
return createPooledOptionalTypeResult(isOptional, type);
}
/**
* Is source potentially coercible to target type under `==`.
@@ -18105,7 +18169,7 @@ namespace ts {
}
function getFlowNodeId(flow: FlowNode): number {
if (!flow.id) {
if (!flow.id || flow.id < 0) {
flow.id = nextFlowId;
nextFlowId++;
}
@@ -18653,7 +18717,7 @@ namespace ts {
// circularities in control flow analysis, we use getTypeOfDottedName when resolving the call
// target expression of an assertion.
const funcType = node.parent.kind === SyntaxKind.ExpressionStatement ? getTypeOfDottedName(node.expression, /*diagnostic*/ undefined) :
node.expression.kind !== SyntaxKind.SuperKeyword ? checkNonNullExpression(node.expression) :
node.expression.kind !== SyntaxKind.SuperKeyword ? checkOptionalExpression(node, node.expression).type :
undefined;
const signatures = getSignaturesOfType(funcType && getApparentType(funcType) || unknownType, SignatureKind.Call);
const candidate = signatures.length === 1 && !signatures[0].typeParameters ? signatures[0] :
@@ -19571,7 +19635,7 @@ namespace ts {
function narrowTypeByCallExpression(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type {
if (hasMatchingArgument(callExpression, reference)) {
const signature = getEffectsSignature(callExpression);
const signature = assumeTrue || !isCallChain(callExpression) ? getEffectsSignature(callExpression) : undefined;
const predicate = signature && getTypePredicateOfSignature(signature);
if (predicate && (predicate.kind === TypePredicateKind.This || predicate.kind === TypePredicateKind.Identifier)) {
return narrowTypeByTypePredicate(type, predicate, callExpression, assumeTrue);
@@ -19614,6 +19678,10 @@ namespace ts {
// Narrow the given type based on the given expression having the assumed boolean value. The returned type
// will be a subtype or the same type as the argument.
function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type {
// for `a?.b`, we emulate a synthetic `a !== null && a !== undefined` condition for `a`
if (isOptionalChainRoot(expr.parent)) {
return narrowTypeByOptionality(type, expr, assumeTrue);
}
switch (expr.kind) {
case SyntaxKind.Identifier:
case SyntaxKind.ThisKeyword:
@@ -19635,6 +19703,19 @@ namespace ts {
}
return type;
}
function narrowTypeByOptionality(type: Type, expr: Expression, assumePresent: boolean): Type {
if (isMatchingReference(reference, expr)) {
return getTypeWithFacts(type, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull);
}
if (isMatchingReferenceDiscriminant(expr, declaredType)) {
return narrowTypeByDiscriminant(type, <AccessExpression>expr, t => getTypeWithFacts(t, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull));
}
if (containsMatchingReferenceDiscriminant(reference, expr)) {
return declaredType;
}
return type;
}
}
function getTypeOfSymbolAtLocation(symbol: Symbol, location: Node) {
@@ -22505,12 +22586,12 @@ namespace ts {
);
}
function isNullableType(type: Type) {
return !!((strictNullChecks ? getFalsyFlags(type) : type.flags) & TypeFlags.Nullable);
}
function getNonNullableTypeIfNeeded(type: Type) {
const kind = (strictNullChecks ? getFalsyFlags(type) : type.flags) & TypeFlags.Nullable;
if (kind) {
return getNonNullableType(type);
}
return type;
return isNullableType(type) ? getNonNullableType(type) : type;
}
function checkNonNullType(
@@ -22561,8 +22642,7 @@ namespace ts {
}
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
let propType: Type;
const leftType = checkNonNullExpression(left);
const { isOptional, type: leftType } = checkOptionalExpression(node, left);
const parentSymbol = getNodeLinks(left).resolvedSymbol;
const assignmentKind = getAssignmentTargetKind(node);
const apparentType = getApparentType(assignmentKind !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(leftType) : leftType);
@@ -22576,6 +22656,8 @@ namespace ts {
if (isIdentifier(left) && parentSymbol && !(prop && isConstEnumOrConstEnumOnlyModule(prop))) {
markAliasReferenced(parentSymbol, node);
}
let propType: Type;
if (!prop) {
const indexInfo = assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) || isThisTypeParameter(leftType) ? getIndexInfoOfType(apparentType, IndexKind.String) : undefined;
if (!(indexInfo && indexInfo.type)) {
@@ -22614,7 +22696,7 @@ namespace ts {
}
propType = getConstraintForLocation(getTypeOfSymbol(prop), node);
}
return getFlowTypeOfAccessExpression(node, prop, propType, right);
return propagateOptionalTypeMarker(getFlowTypeOfAccessExpression(node, prop, propType, right), isOptional);
}
function getFlowTypeOfAccessExpression(node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, prop: Symbol | undefined, propType: Type, errorNode: Node) {
@@ -22971,9 +23053,8 @@ namespace ts {
}
function checkIndexedAccess(node: ElementAccessExpression): Type {
const exprType = checkNonNullExpression(node.expression);
const { isOptional, type: exprType } = checkOptionalExpression(node, node.expression);
const objectType = getAssignmentTargetKind(node) !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(exprType) : exprType;
const indexExpression = node.argumentExpression;
const indexType = checkExpression(indexExpression);
@@ -22991,7 +23072,7 @@ namespace ts {
AccessFlags.Writing | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) ? AccessFlags.NoIndexSignatures : 0) :
AccessFlags.None;
const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, node, accessFlags) || errorType;
return checkIndexedAccessIndexType(getFlowTypeOfAccessExpression(node, indexedAccessType.symbol, indexedAccessType, indexExpression), node);
return propagateOptionalTypeMarker(checkIndexedAccessIndexType(getFlowTypeOfAccessExpression(node, indexedAccessType.symbol, indexedAccessType, indexExpression), node), isOptional);
}
function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean {
@@ -23074,7 +23155,7 @@ namespace ts {
// interface B extends A { (x: 'foo'): string }
// const b: B;
// b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void]
function reorderCandidates(signatures: readonly Signature[], result: Signature[]): void {
function reorderCandidates(signatures: readonly Signature[], result: Signature[], isOptionalCall: boolean): void {
let lastParent: Node | undefined;
let lastSymbol: Symbol | undefined;
let cutoffIndex = 0;
@@ -23116,7 +23197,7 @@ namespace ts {
spliceIndex = index;
}
result.splice(spliceIndex, 0, signature);
result.splice(spliceIndex, 0, isOptionalCall ? createOptionalCallSignature(signature) : signature);
}
}
@@ -23769,7 +23850,7 @@ namespace ts {
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount);
}
function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, fallbackError?: DiagnosticMessage): Signature {
function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, isOptionalCall: boolean, fallbackError?: DiagnosticMessage): Signature {
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
const isDecorator = node.kind === SyntaxKind.Decorator;
const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
@@ -23788,7 +23869,7 @@ namespace ts {
const candidates = candidatesOutArray || [];
// reorderCandidates fills up the candidates array directly
reorderCandidates(signatures, candidates);
reorderCandidates(signatures, candidates, isOptionalCall);
if (!candidates.length) {
if (reportErrors) {
diagnostics.add(getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures));
@@ -24172,13 +24253,14 @@ namespace ts {
const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!);
if (baseTypeNode) {
const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode);
return resolveCall(node, baseConstructors, candidatesOutArray, checkMode);
return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, /*isOptional*/ false);
}
}
return resolveUntypedCall(node);
}
const funcType = checkNonNullExpression(
const { isOptional, type: funcType } = checkOptionalExpression(
node,
node.expression,
Diagnostics.Cannot_invoke_an_object_which_is_possibly_null,
Diagnostics.Cannot_invoke_an_object_which_is_possibly_undefined,
@@ -24188,8 +24270,8 @@ namespace ts {
if (funcType === silentNeverType) {
return silentNeverSignature;
}
const apparentType = getApparentType(funcType);
const apparentType = getApparentType(funcType);
if (apparentType === errorType) {
// Another error has already been reported
return resolveErrorCall(node);
@@ -24253,7 +24335,8 @@ namespace ts {
error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType));
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, candidatesOutArray, checkMode);
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, isOptional);
}
function isGenericFunctionReturningFunction(signature: Signature) {
@@ -24324,7 +24407,7 @@ namespace ts {
return resolveErrorCall(node);
}
return resolveCall(node, constructSignatures, candidatesOutArray, checkMode);
return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, /*isOptional*/ false);
}
// If expressionType's apparent type is an object type with no construct signatures but
@@ -24333,7 +24416,7 @@ namespace ts {
// operation is Any. It is an error to have a Void this type.
const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
if (callSignatures.length) {
const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode);
const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false);
if (!noImplicitAny) {
if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
@@ -24548,7 +24631,7 @@ namespace ts {
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, candidatesOutArray, checkMode);
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false);
}
/**
@@ -24611,7 +24694,7 @@ namespace ts {
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, headMessage);
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false, headMessage);
}
function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature {
@@ -24664,7 +24747,7 @@ namespace ts {
return resolveErrorCall(node);
}
return resolveCall(node, signatures, candidatesOutArray, checkMode);
return resolveCall(node, signatures, candidatesOutArray, checkMode, /*isOptional*/ false);
}
/**
@@ -24851,18 +24934,20 @@ namespace ts {
getTypeOfDottedName(node.expression, diagnostic);
}
}
let jsAssignmentType: Type | undefined;
if (isInJSFile(node)) {
const decl = getDeclarationOfExpando(node);
if (decl) {
const jsSymbol = getSymbolOfNode(decl);
if (jsSymbol && hasEntries(jsSymbol.exports)) {
jsAssignmentType = createAnonymousType(jsSymbol, jsSymbol.exports, emptyArray, emptyArray, undefined, undefined);
(jsAssignmentType as ObjectType).objectFlags |= ObjectFlags.JSLiteral;
const jsAssignmentType = createAnonymousType(jsSymbol, jsSymbol.exports, emptyArray, emptyArray, undefined, undefined);
jsAssignmentType.objectFlags |= ObjectFlags.JSLiteral;
return getIntersectionType([returnType, jsAssignmentType]);
}
}
}
return jsAssignmentType ? getIntersectionType([returnType, jsAssignmentType]) : returnType;
return returnType;
}
function isSymbolOrSymbolForCall(node: Node) {
@@ -24969,7 +25054,7 @@ namespace ts {
}
function checkTaggedTemplateExpression(node: TaggedTemplateExpression): Type {
checkGrammarTypeArguments(node, node.typeArguments);
if (!checkGrammarTaggedTemplateChain(node)) checkGrammarTypeArguments(node, node.typeArguments);
if (languageVersion < ScriptTarget.ES2015) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.MakeTemplateObject);
}
@@ -25886,13 +25971,17 @@ namespace ts {
return false;
}
function checkReferenceExpression(expr: Expression, invalidReferenceMessage: DiagnosticMessage): boolean {
function checkReferenceExpression(expr: Expression, invalidReferenceMessage: DiagnosticMessage, invalidOptionalChainMessage: DiagnosticMessage): boolean {
// References are combinations of identifiers, parentheses, and property accesses.
const node = skipOuterExpressions(expr, OuterExpressionKinds.Assertions | OuterExpressionKinds.Parentheses);
if (node.kind !== SyntaxKind.Identifier && node.kind !== SyntaxKind.PropertyAccessExpression && node.kind !== SyntaxKind.ElementAccessExpression) {
error(expr, invalidReferenceMessage);
return false;
}
if (node.flags & NodeFlags.OptionalChain) {
error(expr, invalidOptionalChainMessage);
return false;
}
return true;
}
@@ -26002,7 +26091,10 @@ namespace ts {
Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type);
if (ok) {
// run check only if former checks succeeded to avoid reporting cascading errors
checkReferenceExpression(node.operand, Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access);
checkReferenceExpression(
node.operand,
Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access,
Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access);
}
return getUnaryResultType(operandType);
}
@@ -26020,7 +26112,10 @@ namespace ts {
Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type);
if (ok) {
// run check only if former checks succeeded to avoid reporting cascading errors
checkReferenceExpression(node.operand, Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access);
checkReferenceExpression(
node.operand,
Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access,
Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access);
}
return getUnaryResultType(operandType);
}
@@ -26270,7 +26365,10 @@ namespace ts {
const error = target.parent.kind === SyntaxKind.SpreadAssignment ?
Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access :
Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access;
if (checkReferenceExpression(target, error)) {
const optionalError = target.parent.kind === SyntaxKind.SpreadAssignment ?
Diagnostics.The_target_of_an_object_rest_assignment_may_not_be_an_optional_property_access :
Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access;
if (checkReferenceExpression(target, error, optionalError)) {
checkTypeAssignableToAndOptionallyElaborate(sourceType, targetType, target, target);
}
return sourceType;
@@ -26476,7 +26574,7 @@ namespace ts {
if (!resultType) {
// Types that have a reasonably good chance of being a valid operand type.
// If both types have an awaited type of one of these, we’ll assume the user
// If both types have an awaited type of one of these, we'll assume the user
// might be missing an await without doing an exhaustive check that inserting
// await(s) will actually be a completely valid binary expression.
const closeEnoughKind = TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.AnyOrUnknown;
@@ -26614,7 +26712,9 @@ namespace ts {
// A compound assignment furthermore requires VarExpr to be classified as a reference (section 4.1)
// and the type of the non-compound operation to be assignable to the type of VarExpr.
if (checkReferenceExpression(left, Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access)
if (checkReferenceExpression(left,
Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access,
Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access)
&& (!isIdentifier(left) || unescapeLeadingUnderscores(left.escapedText) !== "exports")) {
// to avoid cascading errors check assignability only if 'isReference' check succeeded and no errors were reported
checkTypeAssignableToAndOptionallyElaborate(valueType, leftType, left, right);
@@ -27113,11 +27213,11 @@ namespace ts {
const expr = skipParentheses(node);
// Optimize for the common case of a call to a function with a single non-generic call
// signature where we can just fetch the return type without checking the arguments.
if (expr.kind === SyntaxKind.CallExpression && (<CallExpression>expr).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) {
const funcType = checkNonNullExpression((<CallExpression>expr).expression);
if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) {
const { isOptional, type: funcType } = checkOptionalExpression(expr, expr.expression);
const signature = getSingleCallSignature(funcType);
if (signature && !signature.typeParameters) {
return getReturnTypeOfSignature(signature);
return propagateOptionalTypeMarker(getReturnTypeOfSignature(signature), isOptional);
}
}
else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) {
@@ -29958,7 +30058,10 @@ namespace ts {
}
else {
const leftType = checkExpression(varExpr);
checkReferenceExpression(varExpr, Diagnostics.The_left_hand_side_of_a_for_of_statement_must_be_a_variable_or_a_property_access);
checkReferenceExpression(
varExpr,
Diagnostics.The_left_hand_side_of_a_for_of_statement_must_be_a_variable_or_a_property_access,
Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_an_optional_property_access);
// iteratedType will be undefined if the rightType was missing properties/signatures
// required to get its iteratedType (like [Symbol.iterator] or next). This may be
@@ -30008,7 +30111,10 @@ namespace ts {
}
else {
// run check only former check succeeded to avoid cascading errors
checkReferenceExpression(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_a_variable_or_a_property_access);
checkReferenceExpression(
varExpr,
Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_a_variable_or_a_property_access,
Diagnostics.The_left_hand_side_of_a_for_in_statement_may_not_be_an_optional_property_access);
}
}
@@ -34799,6 +34905,13 @@ namespace ts {
checkGrammarForAtLeastOneTypeArgument(node, typeArguments);
}
function checkGrammarTaggedTemplateChain(node: TaggedTemplateExpression): boolean {
if (node.questionDotToken || node.flags & NodeFlags.OptionalChain) {
return grammarErrorOnNode(node.template, Diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain);
}
return false;
}
function checkGrammarForOmittedArgument(args: NodeArray<Expression> | undefined): boolean {
if (args) {
for (const arg of args) {
+9
View File
@@ -187,6 +187,14 @@ namespace ts {
assertNode)
: noop;
export const assertNotNode = shouldAssert(AssertionLevel.Normal)
? (node: Node | undefined, test: ((node: Node | undefined) => boolean) | undefined, message?: string): void => assert(
test === undefined || !test(node),
message || "Unexpected node.",
() => `Node ${formatSyntaxKind(node!.kind)} should not have passed test '${getFunctionName(test!)}'.`,
assertNode)
: noop;
export const assertOptionalNode = shouldAssert(AssertionLevel.Normal)
? (node: Node, test: (node: Node) => boolean, message?: string): void => assert(
test === undefined || node === undefined || test(node),
@@ -260,5 +268,6 @@ namespace ts {
isDebugInfoEnabled = true;
}
}
}
+25
View File
@@ -1039,6 +1039,10 @@
"category": "Error",
"code": 1357
},
"Tagged template expressions are not permitted in an optional chain.": {
"category": "Error",
"code": 1358
},
"The types of '{0}' are incompatible between these types.": {
"category": "Error",
@@ -2747,6 +2751,27 @@
"category": "Error",
"code": 2776
},
"The operand of an increment or decrement operator may not be an optional property access.": {
"category": "Error",
"code": 2777
},
"The target of an object rest assignment may not be an optional property access.": {
"category": "Error",
"code": 2778
},
"The left-hand side of an assignment expression may not be an optional property access.": {
"category": "Error",
"code": 2779
},
"The left-hand side of a 'for...in' statement may not be an optional property access.": {
"category": "Error",
"code": 2780
},
"The left-hand side of a 'for...of' statement may not be an optional property access.": {
"category": "Error",
"code": 2781
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
"code": 4000
+69 -41
View File
@@ -858,6 +858,8 @@ namespace ts {
let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number}[] | undefined;
let hasWrittenComment = false;
let commentsDisabled = !!printerOptions.removeComments;
let lastNode: Node | undefined;
let lastSubstitution: Node | undefined;
const { enter: enterComment, exit: exitComment } = performance.createTimerIf(extendedDiagnostics, "commentTime", "beforeComment", "afterComment");
reset();
@@ -1080,8 +1082,7 @@ namespace ts {
setSourceFile(sourceFile);
}
const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, node);
pipelinePhase(hint, node);
pipelineEmit(hint, node);
}
function setSourceFile(sourceFile: SourceFile | undefined) {
@@ -1113,6 +1114,8 @@ namespace ts {
currentSourceFile = undefined!;
currentLineMap = undefined!;
detachedCommentsInfo = undefined;
lastNode = undefined;
lastSubstitution = undefined;
setWriter(/*output*/ undefined, /*_sourceMapGenerator*/ undefined);
}
@@ -1120,24 +1123,47 @@ namespace ts {
return currentLineMap || (currentLineMap = getLineStarts(currentSourceFile!));
}
function emit(node: Node): Node;
function emit(node: Node | undefined): Node | undefined;
function emit(node: Node | undefined) {
if (node === undefined) return;
const prevSourceFileTextKind = recordBundleFileInternalSectionStart(node);
const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, node);
pipelinePhase(EmitHint.Unspecified, node);
const substitute = pipelineEmit(EmitHint.Unspecified, node);
recordBundleFileInternalSectionEnd(prevSourceFileTextKind);
return substitute;
}
function emitIdentifierName(node: Identifier | undefined) {
function emitIdentifierName(node: Identifier): Node;
function emitIdentifierName(node: Identifier | undefined): Node | undefined;
function emitIdentifierName(node: Identifier | undefined): Node | undefined {
if (node === undefined) return;
const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, node);
pipelinePhase(EmitHint.IdentifierName, node);
return pipelineEmit(EmitHint.IdentifierName, node);
}
function emitExpression(node: Expression | undefined) {
function emitExpression(node: Expression): Node;
function emitExpression(node: Expression | undefined): Node | undefined;
function emitExpression(node: Expression | undefined): Node | undefined {
if (node === undefined) return;
return pipelineEmit(EmitHint.Expression, node);
}
function pipelineEmit(emitHint: EmitHint, node: Node) {
const savedLastNode = lastNode;
const savedLastSubstitution = lastSubstitution;
lastNode = node;
lastSubstitution = undefined;
const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, node);
pipelinePhase(EmitHint.Expression, node);
pipelinePhase(emitHint, node);
Debug.assert(lastNode === node);
const substitute = lastSubstitution;
lastNode = savedLastNode;
lastSubstitution = savedLastSubstitution;
return substitute || node;
}
function getPipelinePhase(phase: PipelinePhase, node: Node) {
@@ -1179,11 +1205,14 @@ namespace ts {
}
function pipelineEmitWithNotification(hint: EmitHint, node: Node) {
Debug.assert(lastNode === node);
const pipelinePhase = getNextPipelinePhase(PipelinePhase.Notification, node);
onEmitNode(hint, node, pipelinePhase);
Debug.assert(lastNode === node);
}
function pipelineEmitWithHint(hint: EmitHint, node: Node): void {
Debug.assert(lastNode === node || lastSubstitution === node);
if (hint === EmitHint.SourceFile) return emitSourceFile(cast(node, isSourceFile));
if (hint === EmitHint.IdentifierName) return emitIdentifier(cast(node, isIdentifier));
if (hint === EmitHint.MappedTypeParameter) return emitMappedTypeParameter(cast(node, isTypeParameterDeclaration));
@@ -1495,7 +1524,7 @@ namespace ts {
if (isExpression(node)) {
hint = EmitHint.Expression;
if (substituteNode !== noEmitSubstitution) {
node = substituteNode(hint, node);
lastSubstitution = node = substituteNode(hint, node);
}
}
else if (isToken(node)) {
@@ -1611,8 +1640,11 @@ namespace ts {
}
function pipelineEmitWithSubstitution(hint: EmitHint, node: Node) {
Debug.assert(lastNode === node || lastSubstitution === node);
const pipelinePhase = getNextPipelinePhase(PipelinePhase.Substitution, node);
pipelinePhase(hint, substituteNode(hint, node));
lastSubstitution = substituteNode(hint, node);
pipelinePhase(hint, lastSubstitution);
Debug.assert(lastNode === node || lastSubstitution === node);
}
function getHelpersFromBundledSourceFiles(bundle: Bundle): string[] | undefined {
@@ -2116,8 +2148,7 @@ namespace ts {
}
writePunctuation("[");
const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, node.typeParameter);
pipelinePhase(EmitHint.MappedTypeParameter, node.typeParameter);
pipelineEmit(EmitHint.MappedTypeParameter, node.typeParameter);
writePunctuation("]");
if (node.questionToken) {
@@ -2215,34 +2246,24 @@ namespace ts {
}
function emitPropertyAccessExpression(node: PropertyAccessExpression) {
let indentBeforeDot = false;
let indentAfterDot = false;
const dotRangeFirstCommentStart = skipTrivia(
currentSourceFile!.text,
node.expression.end,
/*stopAfterLineBreak*/ false,
/*stopAtComments*/ true
);
const dotRangeStart = skipTrivia(currentSourceFile!.text, dotRangeFirstCommentStart);
const dotRangeEnd = dotRangeStart + 1;
if (!(getEmitFlags(node) & EmitFlags.NoIndentation)) {
const dotToken = createToken(SyntaxKind.DotToken);
dotToken.pos = node.expression.end;
dotToken.end = dotRangeEnd;
indentBeforeDot = needsIndentation(node, node.expression, dotToken);
indentAfterDot = needsIndentation(node, dotToken, node.name);
}
const expression = cast(emitExpression(node.expression), isExpression);
const token = getDotOrQuestionDotToken(node);
const indentBeforeDot = needsIndentation(node, node.expression, token);
const indentAfterDot = needsIndentation(node, token, node.name);
emitExpression(node.expression);
increaseIndentIf(indentBeforeDot, /*writeSpaceIfNotIndenting*/ false);
const dotHasCommentTrivia = dotRangeFirstCommentStart !== dotRangeStart;
const shouldEmitDotDot = !indentBeforeDot && needsDotDotForPropertyAccess(node.expression, dotHasCommentTrivia);
const shouldEmitDotDot =
token.kind !== SyntaxKind.QuestionDotToken &&
mayNeedDotDotForPropertyAccess(expression) &&
!writer.hasTrailingComment() &&
!writer.hasTrailingWhitespace();
if (shouldEmitDotDot) {
writePunctuation(".");
}
emitTokenWithComment(SyntaxKind.DotToken, node.expression.end, writePunctuation, node);
emitTokenWithComment(token.kind, node.expression.end, writePunctuation, node);
increaseIndentIf(indentAfterDot, /*writeSpaceIfNotIndenting*/ false);
emit(node.name);
decreaseIndentIf(indentBeforeDot, indentAfterDot);
@@ -2250,28 +2271,27 @@ namespace ts {
// 1..toString is a valid property access, emit a dot after the literal
// Also emit a dot if expression is a integer const enum value - it will appear in generated code as numeric literal
function needsDotDotForPropertyAccess(expression: Expression, dotHasTrivia: boolean) {
function mayNeedDotDotForPropertyAccess(expression: Expression) {
expression = skipPartiallyEmittedExpressions(expression);
if (isNumericLiteral(expression)) {
// check if numeric literal is a decimal literal that was originally written with a dot
const text = getLiteralTextOfNode(<LiteralExpression>expression, /*neverAsciiEscape*/ true);
// If he number will be printed verbatim and it doesn't already contain a dot, add one
// if the expression doesn't have any comments that will be emitted.
return !expression.numericLiteralFlags && !stringContains(text, tokenToString(SyntaxKind.DotToken)!) &&
(!dotHasTrivia || printerOptions.removeComments);
return !expression.numericLiteralFlags && !stringContains(text, tokenToString(SyntaxKind.DotToken)!);
}
else if (isPropertyAccessExpression(expression) || isElementAccessExpression(expression)) {
// check if constant enum value is integer
const constantValue = getConstantValue(expression);
// isFinite handles cases when constantValue is undefined
return typeof constantValue === "number" && isFinite(constantValue)
&& Math.floor(constantValue) === constantValue
&& printerOptions.removeComments;
&& Math.floor(constantValue) === constantValue;
}
}
function emitElementAccessExpression(node: ElementAccessExpression) {
emitExpression(node.expression);
emit(node.questionDotToken);
emitTokenWithComment(SyntaxKind.OpenBracketToken, node.expression.end, writePunctuation, node);
emitExpression(node.argumentExpression);
emitTokenWithComment(SyntaxKind.CloseBracketToken, node.argumentExpression.end, writePunctuation, node);
@@ -2279,6 +2299,7 @@ namespace ts {
function emitCallExpression(node: CallExpression) {
emitExpression(node.expression);
emit(node.questionDotToken);
emitTypeArguments(node, node.typeArguments);
emitExpressionList(node, node.arguments, ListFormat.CallExpressionArguments);
}
@@ -3742,8 +3763,7 @@ namespace ts {
writeLine();
increaseIndent();
if (isEmptyStatement(node)) {
const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, node);
pipelinePhase(EmitHint.EmbeddedStatement, node);
pipelineEmit(EmitHint.EmbeddedStatement, node);
}
else {
emit(node);
@@ -4214,6 +4234,10 @@ namespace ts {
}
function needsIndentation(parent: Node, node1: Node, node2: Node): boolean {
if (getEmitFlags(parent) & EmitFlags.NoIndentation) {
return false;
}
parent = skipSynthesizedParentheses(parent);
node1 = skipSynthesizedParentheses(node1);
node2 = skipSynthesizedParentheses(node2);
@@ -4669,6 +4693,7 @@ namespace ts {
// Comments
function pipelineEmitWithComments(hint: EmitHint, node: Node) {
Debug.assert(lastNode === node || lastSubstitution === node);
enterComment();
hasWrittenComment = false;
const emitFlags = getEmitFlags(node);
@@ -4735,6 +4760,7 @@ namespace ts {
}
}
exitComment();
Debug.assert(lastNode === node || lastSubstitution === node);
}
function emitLeadingSynthesizedComment(comment: SynthesizedComment) {
@@ -4981,6 +5007,7 @@ namespace ts {
}
function pipelineEmitWithSourceMap(hint: EmitHint, node: Node) {
Debug.assert(lastNode === node || lastSubstitution === node);
const pipelinePhase = getNextPipelinePhase(PipelinePhase.SourceMaps, node);
if (isUnparsedSource(node) || isUnparsedPrepend(node)) {
pipelinePhase(hint, node);
@@ -5023,6 +5050,7 @@ namespace ts {
emitSourcePos(source, end);
}
}
Debug.assert(lastNode === node || lastSubstitution === node);
}
/**
+78
View File
@@ -1065,6 +1065,7 @@ namespace ts {
}
export function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier) {
Debug.assert(!(node.flags & NodeFlags.OptionalChain), "Cannot update a PropertyAccessChain using updatePropertyAccess. Use updatePropertyAccessChain instead.");
// Because we are updating existed propertyAccess we want to inherit its emitFlags
// instead of using the default from createPropertyAccess
return node.expression !== expression
@@ -1073,6 +1074,27 @@ namespace ts {
: node;
}
export function createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier) {
const node = <PropertyAccessChain>createSynthesizedNode(SyntaxKind.PropertyAccessExpression);
node.flags |= NodeFlags.OptionalChain;
node.expression = parenthesizeForAccess(expression);
node.questionDotToken = questionDotToken;
node.name = asName(name);
setEmitFlags(node, EmitFlags.NoIndentation);
return node;
}
export function updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier) {
Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a PropertyAccessExpression using updatePropertyAccessChain. Use updatePropertyAccess instead.");
// Because we are updating an existing PropertyAccessChain we want to inherit its emitFlags
// instead of using the default from createPropertyAccess
return node.expression !== expression
|| node.questionDotToken !== questionDotToken
|| node.name !== name
? updateNode(setEmitFlags(createPropertyAccessChain(expression, questionDotToken, name), getEmitFlags(node)), node)
: node;
}
export function createElementAccess(expression: Expression, index: number | Expression) {
const node = <ElementAccessExpression>createSynthesizedNode(SyntaxKind.ElementAccessExpression);
node.expression = parenthesizeForAccess(expression);
@@ -1081,12 +1103,31 @@ namespace ts {
}
export function updateElementAccess(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression) {
Debug.assert(!(node.flags & NodeFlags.OptionalChain), "Cannot update an ElementAccessChain using updateElementAccess. Use updateElementAccessChain instead.");
return node.expression !== expression
|| node.argumentExpression !== argumentExpression
? updateNode(createElementAccess(expression, argumentExpression), node)
: node;
}
export function createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression) {
const node = <ElementAccessChain>createSynthesizedNode(SyntaxKind.ElementAccessExpression);
node.flags |= NodeFlags.OptionalChain;
node.expression = parenthesizeForAccess(expression);
node.questionDotToken = questionDotToken;
node.argumentExpression = asExpression(index);
return node;
}
export function updateElementAccessChain(node: ElementAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, argumentExpression: Expression) {
Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update an ElementAccessExpression using updateElementAccessChain. Use updateElementAccess instead.");
return node.expression !== expression
|| node.questionDotToken !== questionDotToken
|| node.argumentExpression !== argumentExpression
? updateNode(createElementAccessChain(expression, questionDotToken, argumentExpression), node)
: node;
}
export function createCall(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
const node = <CallExpression>createSynthesizedNode(SyntaxKind.CallExpression);
node.expression = parenthesizeForAccess(expression);
@@ -1096,6 +1137,7 @@ namespace ts {
}
export function updateCall(node: CallExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) {
Debug.assert(!(node.flags & NodeFlags.OptionalChain), "Cannot update a CallChain using updateCall. Use updateCallChain instead.");
return node.expression !== expression
|| node.typeArguments !== typeArguments
|| node.arguments !== argumentsArray
@@ -1103,6 +1145,26 @@ namespace ts {
: node;
}
export function createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
const node = <CallChain>createSynthesizedNode(SyntaxKind.CallExpression);
node.flags |= NodeFlags.OptionalChain;
node.expression = parenthesizeForAccess(expression);
node.questionDotToken = questionDotToken;
node.typeArguments = asNodeArray(typeArguments);
node.arguments = parenthesizeListElements(createNodeArray(argumentsArray));
return node;
}
export function updateCallChain(node: CallChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) {
Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a CallExpression using updateCallChain. Use updateCall instead.");
return node.expression !== expression
|| node.questionDotToken !== questionDotToken
|| node.typeArguments !== typeArguments
|| node.arguments !== argumentsArray
? updateNode(createCallChain(expression, questionDotToken, typeArguments, argumentsArray), node)
: node;
}
export function createNew(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
const node = <NewExpression>createSynthesizedNode(SyntaxKind.NewExpression);
node.expression = parenthesizeForNew(expression);
@@ -2776,6 +2838,22 @@ namespace ts {
: node;
}
/* @internal */
export function createSyntheticReferenceExpression(expression: Expression, thisArg: Expression) {
const node = <SyntheticReferenceExpression>createSynthesizedNode(SyntaxKind.SyntheticReferenceExpression);
node.expression = expression;
node.thisArg = thisArg;
return node;
}
/* @internal */
export function updateSyntheticReferenceExpression(node: SyntheticReferenceExpression, expression: Expression, thisArg: Expression) {
return node.expression !== expression
|| node.thisArg !== thisArg
? updateNode(createSyntheticReferenceExpression(expression, thisArg), node)
: node;
}
export function createBundle(sourceFiles: readonly SourceFile[], prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray) {
const node = <Bundle>createNode(SyntaxKind.Bundle);
node.prepends = prepends;
+109 -46
View File
@@ -212,17 +212,21 @@ namespace ts {
return visitNodes(cbNode, cbNodes, (<ObjectLiteralExpression>node).properties);
case SyntaxKind.PropertyAccessExpression:
return visitNode(cbNode, (<PropertyAccessExpression>node).expression) ||
visitNode(cbNode, (<PropertyAccessExpression>node).questionDotToken) ||
visitNode(cbNode, (<PropertyAccessExpression>node).name);
case SyntaxKind.ElementAccessExpression:
return visitNode(cbNode, (<ElementAccessExpression>node).expression) ||
visitNode(cbNode, (<ElementAccessExpression>node).questionDotToken) ||
visitNode(cbNode, (<ElementAccessExpression>node).argumentExpression);
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
return visitNode(cbNode, (<CallExpression>node).expression) ||
visitNode(cbNode, (<CallExpression>node).questionDotToken) ||
visitNodes(cbNode, cbNodes, (<CallExpression>node).typeArguments) ||
visitNodes(cbNode, cbNodes, (<CallExpression>node).arguments);
case SyntaxKind.TaggedTemplateExpression:
return visitNode(cbNode, (<TaggedTemplateExpression>node).tag) ||
visitNode(cbNode, (<TaggedTemplateExpression>node).questionDotToken) ||
visitNodes(cbNode, cbNodes, (<TaggedTemplateExpression>node).typeArguments) ||
visitNode(cbNode, (<TaggedTemplateExpression>node).template);
case SyntaxKind.TypeAssertionExpression:
@@ -4243,7 +4247,8 @@ namespace ts {
}
// Now, we *may* be complete. However, we might have consumed the start of a
// CallExpression. As such, we need to consume the rest of it here to be complete.
// CallExpression or OptionalExpression. As such, we need to consume the rest
// of it here to be complete.
return parseCallExpressionRest(expression);
}
@@ -4296,7 +4301,7 @@ namespace ts {
// Because CallExpression and MemberExpression are left recursive, we need to bottom out
// of the recursion immediately. So we parse out a primary expression to start with.
const expression = parsePrimaryExpression();
return parseMemberExpressionRest(expression);
return parseMemberExpressionRest(expression, /*allowOptionalChain*/ true);
}
function parseSuperExpression(): MemberExpression {
@@ -4590,18 +4595,70 @@ namespace ts {
return finishNode(node);
}
function parseMemberExpressionRest(expression: LeftHandSideExpression): MemberExpression {
function nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate() {
nextToken();
return tokenIsIdentifierOrKeyword(token())
|| token() === SyntaxKind.OpenBracketToken
|| isTemplateStartOfTaggedTemplate();
}
function isStartOfOptionalPropertyOrElementAccessChain() {
return token() === SyntaxKind.QuestionDotToken
&& lookAhead(nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate);
}
function parsePropertyAccessExpressionRest(expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {
const propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
propertyAccess.expression = expression;
propertyAccess.questionDotToken = questionDotToken;
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
propertyAccess.flags |= NodeFlags.OptionalChain;
}
return finishNode(propertyAccess);
}
function parseElementAccessExpressionRest(expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {
const indexedAccess = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression, expression.pos);
indexedAccess.expression = expression;
indexedAccess.questionDotToken = questionDotToken;
if (token() === SyntaxKind.CloseBracketToken) {
indexedAccess.argumentExpression = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.An_element_access_expression_should_take_an_argument);
}
else {
const argument = allowInAnd(parseExpression);
if (isStringOrNumericLiteralLike(argument)) {
argument.text = internIdentifier(argument.text);
}
indexedAccess.argumentExpression = argument;
}
parseExpected(SyntaxKind.CloseBracketToken);
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
indexedAccess.flags |= NodeFlags.OptionalChain;
}
return finishNode(indexedAccess);
}
function parseMemberExpressionRest(expression: LeftHandSideExpression, allowOptionalChain: boolean): MemberExpression {
while (true) {
const dotToken = parseOptionalToken(SyntaxKind.DotToken);
if (dotToken) {
const propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
propertyAccess.expression = expression;
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
expression = finishNode(propertyAccess);
let questionDotToken: QuestionDotToken | undefined;
let isPropertyAccess = false;
if (allowOptionalChain && isStartOfOptionalPropertyOrElementAccessChain()) {
questionDotToken = parseExpectedToken(SyntaxKind.QuestionDotToken);
isPropertyAccess = tokenIsIdentifierOrKeyword(token());
}
else {
isPropertyAccess = parseOptional(SyntaxKind.DotToken);
}
if (isPropertyAccess) {
expression = parsePropertyAccessExpressionRest(expression, questionDotToken);
continue;
}
if (token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
if (!questionDotToken && token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
nextToken();
const nonNullExpression = <NonNullExpression>createNode(SyntaxKind.NonNullExpression, expression.pos);
nonNullExpression.expression = expression;
@@ -4610,28 +4667,13 @@ namespace ts {
}
// when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName
if (!inDecoratorContext() && parseOptional(SyntaxKind.OpenBracketToken)) {
const indexedAccess = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression, expression.pos);
indexedAccess.expression = expression;
if (token() === SyntaxKind.CloseBracketToken) {
indexedAccess.argumentExpression = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.An_element_access_expression_should_take_an_argument);
}
else {
const argument = allowInAnd(parseExpression);
if (isStringOrNumericLiteralLike(argument)) {
argument.text = internIdentifier(argument.text);
}
indexedAccess.argumentExpression = argument;
}
parseExpected(SyntaxKind.CloseBracketToken);
expression = finishNode(indexedAccess);
if ((questionDotToken || !inDecoratorContext()) && parseOptional(SyntaxKind.OpenBracketToken)) {
expression = parseElementAccessExpressionRest(expression, questionDotToken);
continue;
}
if (isTemplateStartOfTaggedTemplate()) {
expression = parseTaggedTemplateRest(expression, /*typeArguments*/ undefined);
expression = parseTaggedTemplateRest(expression, questionDotToken, /*typeArguments*/ undefined);
continue;
}
@@ -4643,19 +4685,25 @@ namespace ts {
return token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead;
}
function parseTaggedTemplateRest(tag: LeftHandSideExpression, typeArguments: NodeArray<TypeNode> | undefined) {
function parseTaggedTemplateRest(tag: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined, typeArguments: NodeArray<TypeNode> | undefined) {
const tagExpression = <TaggedTemplateExpression>createNode(SyntaxKind.TaggedTemplateExpression, tag.pos);
tagExpression.tag = tag;
tagExpression.questionDotToken = questionDotToken;
tagExpression.typeArguments = typeArguments;
tagExpression.template = token() === SyntaxKind.NoSubstitutionTemplateLiteral
? <NoSubstitutionTemplateLiteral>parseLiteralNode()
: parseTemplateExpression();
if (questionDotToken || tag.flags & NodeFlags.OptionalChain) {
tagExpression.flags |= NodeFlags.OptionalChain;
}
return finishNode(tagExpression);
}
function parseCallExpressionRest(expression: LeftHandSideExpression): LeftHandSideExpression {
while (true) {
expression = parseMemberExpressionRest(expression);
expression = parseMemberExpressionRest(expression, /*allowOptionalChain*/ true);
const questionDotToken = parseOptionalToken(SyntaxKind.QuestionDotToken);
// handle 'foo<<T>()'
if (token() === SyntaxKind.LessThanToken || token() === SyntaxKind.LessThanLessThanToken) {
// See if this is the start of a generic invocation. If so, consume it and
@@ -4663,32 +4711,47 @@ namespace ts {
// part of an arithmetic expression. Break out so we consume it higher in the
// stack.
const typeArguments = tryParse(parseTypeArgumentsInExpression);
if (!typeArguments) {
return expression;
}
if (typeArguments) {
if (isTemplateStartOfTaggedTemplate()) {
expression = parseTaggedTemplateRest(expression, questionDotToken, typeArguments);
continue;
}
if (isTemplateStartOfTaggedTemplate()) {
expression = parseTaggedTemplateRest(expression, typeArguments);
const callExpr = <CallExpression>createNode(SyntaxKind.CallExpression, expression.pos);
callExpr.expression = expression;
callExpr.questionDotToken = questionDotToken;
callExpr.typeArguments = typeArguments;
callExpr.arguments = parseArgumentList();
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
callExpr.flags |= NodeFlags.OptionalChain;
}
expression = finishNode(callExpr);
continue;
}
const callExpr = <CallExpression>createNode(SyntaxKind.CallExpression, expression.pos);
callExpr.expression = expression;
callExpr.typeArguments = typeArguments;
callExpr.arguments = parseArgumentList();
expression = finishNode(callExpr);
continue;
}
else if (token() === SyntaxKind.OpenParenToken) {
const callExpr = <CallExpression>createNode(SyntaxKind.CallExpression, expression.pos);
callExpr.expression = expression;
callExpr.questionDotToken = questionDotToken;
callExpr.arguments = parseArgumentList();
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
callExpr.flags |= NodeFlags.OptionalChain;
}
expression = finishNode(callExpr);
continue;
}
return expression;
if (questionDotToken) {
// We failed to parse anything, so report a missing identifier here.
const propertyAccess = createNode(SyntaxKind.PropertyAccessExpression, expression.pos) as PropertyAccessExpression;
propertyAccess.expression = expression;
propertyAccess.questionDotToken = questionDotToken;
propertyAccess.name = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics.Identifier_expected);
propertyAccess.flags |= NodeFlags.OptionalChain;
expression = finishNode(propertyAccess);
}
break;
}
return expression;
}
function parseArgumentList() {
@@ -4957,12 +5020,12 @@ namespace ts {
let expression: MemberExpression = parsePrimaryExpression();
let typeArguments;
while (true) {
expression = parseMemberExpressionRest(expression);
expression = parseMemberExpressionRest(expression, /*allowOptionalChain*/ false);
typeArguments = tryParse(parseTypeArgumentsInExpression);
if (isTemplateStartOfTaggedTemplate()) {
Debug.assert(!!typeArguments,
"Expected a type argument list; all plain tagged template starts should be consumed in 'parseMemberExpressionRest'");
expression = parseTaggedTemplateRest(expression, typeArguments);
expression = parseTaggedTemplateRest(expression, /*optionalChain*/ undefined, typeArguments);
typeArguments = undefined;
}
break;
+5
View File
@@ -184,6 +184,7 @@ namespace ts {
"&&": SyntaxKind.AmpersandAmpersandToken,
"||": SyntaxKind.BarBarToken,
"?": SyntaxKind.QuestionToken,
"?.": SyntaxKind.QuestionDotToken,
":": SyntaxKind.ColonToken,
"=": SyntaxKind.EqualsToken,
"+=": SyntaxKind.PlusEqualsToken,
@@ -1829,6 +1830,10 @@ namespace ts {
return token = SyntaxKind.GreaterThanToken;
case CharacterCodes.question:
pos++;
if (text.charCodeAt(pos) === CharacterCodes.dot && !isDigit(text.charCodeAt(pos + 1))) {
pos++;
return token = SyntaxKind.QuestionDotToken;
}
return token = SyntaxKind.QuestionToken;
case CharacterCodes.openBracket:
pos++;
+152
View File
@@ -1,6 +1,10 @@
/*@internal*/
namespace ts {
export function transformESNext(context: TransformationContext) {
const {
hoistVariableDeclaration
} = context;
return chainBundle(transformSourceFile);
function transformSourceFile(node: SourceFile) {
@@ -16,9 +20,157 @@ namespace ts {
return node;
}
switch (node.kind) {
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.CallExpression:
if (node.flags & NodeFlags.OptionalChain) {
const updated = visitOptionalExpression(node as OptionalChain, /*captureThisArg*/ false);
Debug.assertNotNode(updated, isSyntheticReference);
return updated;
}
// falls through
default:
return visitEachChild(node, visitor, context);
}
}
function flattenChain(chain: OptionalChain) {
const links: OptionalChain[] = [chain];
while (!chain.questionDotToken && !isTaggedTemplateExpression(chain)) {
chain = cast(chain.expression, isOptionalChain);
links.unshift(chain);
}
return { expression: chain.expression, chain: links };
}
function visitNonOptionalParenthesizedExpression(node: ParenthesizedExpression, captureThisArg: boolean): Expression {
const expression = visitNonOptionalExpression(node.expression, captureThisArg);
if (isSyntheticReference(expression)) {
// `(a.b)` -> { expression `((_a = a).b)`, thisArg: `_a` }
// `(a[b])` -> { expression `((_a = a)[b])`, thisArg: `_a` }
return createSyntheticReferenceExpression(updateParen(node, expression.expression), expression.thisArg);
}
return updateParen(node, expression);
}
function visitNonOptionalPropertyAccessExpression(node: PropertyAccessExpression, captureThisArg: boolean): Expression {
if (isOptionalChain(node)) {
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
return visitOptionalExpression(node, captureThisArg);
}
let expression = visitNode(node.expression, visitor, isExpression);
Debug.assertNotNode(expression, isSyntheticReference);
let thisArg: Expression | undefined;
if (captureThisArg) {
// `a.b` -> { expression: `(_a = a).b`, thisArg: `_a` }
thisArg = createTempVariable(hoistVariableDeclaration);
expression = createParen(createAssignment(thisArg, expression));
}
expression = updatePropertyAccess(node, expression, visitNode(node.name, visitor, isIdentifier));
return thisArg ? createSyntheticReferenceExpression(expression, thisArg) : expression;
}
function visitNonOptionalElementAccessExpression(node: ElementAccessExpression, captureThisArg: boolean): Expression {
if (isOptionalChain(node)) {
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
return visitOptionalExpression(node, captureThisArg);
}
let expression = visitNode(node.expression, visitor, isExpression);
Debug.assertNotNode(expression, isSyntheticReference);
let thisArg: Expression | undefined;
if (captureThisArg) {
// `a[b]` -> { expression: `(_a = a)[b]`, thisArg: `_a` }
thisArg = createTempVariable(hoistVariableDeclaration);
expression = createParen(createAssignment(thisArg, expression));
}
expression = updateElementAccess(node, expression, visitNode(node.argumentExpression, visitor, isExpression));
return thisArg ? createSyntheticReferenceExpression(expression, thisArg) : expression;
}
function visitNonOptionalCallExpression(node: CallExpression, captureThisArg: boolean): Expression {
if (isOptionalChain(node)) {
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
return visitOptionalExpression(node, captureThisArg);
}
return visitEachChild(node, visitor, context);
}
function visitNonOptionalExpression(node: Expression, captureThisArg: boolean): Expression {
switch (node.kind) {
case SyntaxKind.ParenthesizedExpression: return visitNonOptionalParenthesizedExpression(node as ParenthesizedExpression, captureThisArg);
case SyntaxKind.PropertyAccessExpression: return visitNonOptionalPropertyAccessExpression(node as PropertyAccessExpression, captureThisArg);
case SyntaxKind.ElementAccessExpression: return visitNonOptionalElementAccessExpression(node as ElementAccessExpression, captureThisArg);
case SyntaxKind.CallExpression: return visitNonOptionalCallExpression(node as CallExpression, captureThisArg);
default: return visitNode(node, visitor, isExpression);
}
}
function visitOptionalExpression(node: OptionalChain, captureThisArg: boolean): Expression {
const { expression, chain } = flattenChain(node);
const left = visitNonOptionalExpression(expression, isCallChain(chain[0]));
const temp = createTempVariable(hoistVariableDeclaration);
const leftThisArg = isSyntheticReference(left) ? left.thisArg : undefined;
const leftExpression = isSyntheticReference(left) ? left.expression : left;
let rightExpression: Expression = temp;
let thisArg: Expression | undefined;
for (let i = 0; i < chain.length; i++) {
const segment = chain[i];
switch (segment.kind) {
case SyntaxKind.PropertyAccessExpression:
if (i === chain.length - 1 && captureThisArg) {
thisArg = createTempVariable(hoistVariableDeclaration);
rightExpression = createParen(createAssignment(thisArg, rightExpression));
}
rightExpression = createPropertyAccess(
rightExpression,
visitNode(segment.name, visitor, isIdentifier)
);
break;
case SyntaxKind.ElementAccessExpression:
if (i === chain.length - 1 && captureThisArg) {
thisArg = createTempVariable(hoistVariableDeclaration);
rightExpression = createParen(createAssignment(thisArg, rightExpression));
}
rightExpression = createElementAccess(
rightExpression,
visitNode(segment.argumentExpression, visitor, isExpression)
);
break;
case SyntaxKind.CallExpression:
if (i === 0 && leftThisArg) {
rightExpression = createFunctionCall(
rightExpression,
leftThisArg,
visitNodes(segment.arguments, visitor, isExpression)
);
}
else {
rightExpression = createCall(
rightExpression,
/*typeArguments*/ undefined,
visitNodes(segment.arguments, visitor, isExpression)
);
}
break;
}
setOriginalNode(rightExpression, segment);
}
const target = createConditional(
createLogicalOr(
createStrictEquality(createAssignment(temp, leftExpression), createNull()),
createStrictEquality(temp, createVoidZero())
),
createVoidZero(),
rightExpression
);
return thisArg ? createSyntheticReferenceExpression(target, thisArg) : target;
}
}
}
+85 -21
View File
@@ -152,6 +152,7 @@ namespace ts {
DotDotDotToken,
SemicolonToken,
CommaToken,
QuestionDotToken,
LessThanToken,
LessThanSlashToken,
GreaterThanToken,
@@ -485,6 +486,7 @@ namespace ts {
CommaListExpression,
MergeDeclarationMarker,
EndOfDeclarationMarker,
SyntheticReferenceExpression,
// Enum value count
Count,
@@ -532,20 +534,21 @@ namespace ts {
NestedNamespace = 1 << 2, // Namespace declaration
Synthesized = 1 << 3, // Node was synthesized during transformation
Namespace = 1 << 4, // Namespace declaration
ExportContext = 1 << 5, // Export context (initialized by binding)
ContainsThis = 1 << 6, // Interface contains references to "this"
HasImplicitReturn = 1 << 7, // If function implicitly returns on one of codepaths (initialized by binding)
HasExplicitReturn = 1 << 8, // If function has explicit reachable return on one of codepaths (initialized by binding)
GlobalAugmentation = 1 << 9, // Set if module declaration is an augmentation for the global scope
HasAsyncFunctions = 1 << 10, // If the file has async functions (initialized by binding)
DisallowInContext = 1 << 11, // If node was parsed in a context where 'in-expressions' are not allowed
YieldContext = 1 << 12, // If node was parsed in the 'yield' context created when parsing a generator
DecoratorContext = 1 << 13, // If node was parsed as part of a decorator
AwaitContext = 1 << 14, // If node was parsed in the 'await' context created when parsing an async function
ThisNodeHasError = 1 << 15, // If the parser encountered an error when parsing the code that created this node
JavaScriptFile = 1 << 16, // If node was parsed in a JavaScript
ThisNodeOrAnySubNodesHasError = 1 << 17, // If this node or any of its children had an error
HasAggregatedChildData = 1 << 18, // If we've computed data from children and cached it in this node
OptionalChain = 1 << 5, // Chained MemberExpression rooted to a pseudo-OptionalExpression
ExportContext = 1 << 6, // Export context (initialized by binding)
ContainsThis = 1 << 7, // Interface contains references to "this"
HasImplicitReturn = 1 << 8, // If function implicitly returns on one of codepaths (initialized by binding)
HasExplicitReturn = 1 << 9, // If function has explicit reachable return on one of codepaths (initialized by binding)
GlobalAugmentation = 1 << 10, // Set if module declaration is an augmentation for the global scope
HasAsyncFunctions = 1 << 11, // If the file has async functions (initialized by binding)
DisallowInContext = 1 << 12, // If node was parsed in a context where 'in-expressions' are not allowed
YieldContext = 1 << 13, // If node was parsed in the 'yield' context created when parsing a generator
DecoratorContext = 1 << 14, // If node was parsed as part of a decorator
AwaitContext = 1 << 15, // If node was parsed in the 'await' context created when parsing an async function
ThisNodeHasError = 1 << 16, // If the parser encountered an error when parsing the code that created this node
JavaScriptFile = 1 << 17, // If node was parsed in a JavaScript
ThisNodeOrAnySubNodesHasError = 1 << 18, // If this node or any of its children had an error
HasAggregatedChildData = 1 << 19, // If we've computed data from children and cached it in this node
// These flags will be set when the parser encounters a dynamic import expression or 'import.meta' to avoid
// walking the tree if the flags are not set. However, these flags are just a approximation
@@ -556,13 +559,13 @@ namespace ts {
// removal, it is likely that users will add the import anyway.
// The advantage of this approach is its simplicity. For the case of batch compilation,
// we guarantee that users won't have to pay the price of walking the tree if a dynamic import isn't used.
/* @internal */ PossiblyContainsDynamicImport = 1 << 19,
/* @internal */ PossiblyContainsImportMeta = 1 << 20,
/* @internal */ PossiblyContainsDynamicImport = 1 << 20,
/* @internal */ PossiblyContainsImportMeta = 1 << 21,
JSDoc = 1 << 21, // If node was parsed inside jsdoc
/* @internal */ Ambient = 1 << 22, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier.
/* @internal */ InWithStatement = 1 << 23, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`)
JsonFile = 1 << 24, // If node was parsed in a Json
JSDoc = 1 << 22, // If node was parsed inside jsdoc
/* @internal */ Ambient = 1 << 23, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier.
/* @internal */ InWithStatement = 1 << 24, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`)
JsonFile = 1 << 25, // If node was parsed in a Json
BlockScoped = Let | Const,
@@ -732,8 +735,10 @@ namespace ts {
kind: TKind;
}
export type DotToken = Token<SyntaxKind.DotToken>;
export type DotDotDotToken = Token<SyntaxKind.DotDotDotToken>;
export type QuestionToken = Token<SyntaxKind.QuestionToken>;
export type QuestionDotToken = Token<SyntaxKind.QuestionDotToken>;
export type ExclamationToken = Token<SyntaxKind.ExclamationToken>;
export type ColonToken = Token<SyntaxKind.ColonToken>;
export type EqualsToken = Token<SyntaxKind.EqualsToken>;
@@ -1803,9 +1808,19 @@ namespace ts {
export interface PropertyAccessExpression extends MemberExpression, NamedDeclaration {
kind: SyntaxKind.PropertyAccessExpression;
expression: LeftHandSideExpression;
questionDotToken?: QuestionDotToken;
name: Identifier;
}
export interface PropertyAccessChain extends PropertyAccessExpression {
_optionalChainBrand: any;
}
/* @internal */
export interface PropertyAccessChainRoot extends PropertyAccessChain {
questionDotToken: QuestionDotToken;
}
export interface SuperPropertyAccessExpression extends PropertyAccessExpression {
expression: SuperExpression;
}
@@ -1819,9 +1834,19 @@ namespace ts {
export interface ElementAccessExpression extends MemberExpression {
kind: SyntaxKind.ElementAccessExpression;
expression: LeftHandSideExpression;
questionDotToken?: QuestionDotToken;
argumentExpression: Expression;
}
export interface ElementAccessChain extends ElementAccessExpression {
_optionalChainBrand: any;
}
/* @internal */
export interface ElementAccessChainRoot extends ElementAccessChain {
questionDotToken: QuestionDotToken;
}
export interface SuperElementAccessExpression extends ElementAccessExpression {
expression: SuperExpression;
}
@@ -1832,10 +1857,33 @@ namespace ts {
export interface CallExpression extends LeftHandSideExpression, Declaration {
kind: SyntaxKind.CallExpression;
expression: LeftHandSideExpression;
questionDotToken?: QuestionDotToken;
typeArguments?: NodeArray<TypeNode>;
arguments: NodeArray<Expression>;
}
export interface CallChain extends CallExpression {
_optionalChainBrand: any;
}
/* @internal */
export interface CallChainRoot extends CallChain {
questionDotToken: QuestionDotToken;
}
export type OptionalChain =
| PropertyAccessChain
| ElementAccessChain
| CallChain
;
/* @internal */
export type OptionalChainRoot =
| PropertyAccessChainRoot
| ElementAccessChainRoot
| CallChainRoot
;
/** @internal */
export type BindableObjectDefinePropertyCall = CallExpression & { arguments: { 0: EntityNameExpression, 1: StringLiteralLike | NumericLiteral, 2: ObjectLiteralExpression } };
@@ -1866,6 +1914,7 @@ namespace ts {
tag: LeftHandSideExpression;
typeArguments?: NodeArray<TypeNode>;
template: TemplateLiteral;
/*@internal*/ questionDotToken?: QuestionDotToken; // NOTE: Invalid syntax, only used to report a grammar error.
}
export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression | Decorator | JsxOpeningLikeElement;
@@ -2033,6 +2082,13 @@ namespace ts {
kind: SyntaxKind.MergeDeclarationMarker;
}
/* @internal */
export interface SyntheticReferenceExpression extends LeftHandSideExpression {
kind: SyntaxKind.SyntheticReferenceExpression;
expression: Expression;
thisArg: Expression;
}
export interface EmptyStatement extends Statement {
kind: SyntaxKind.EmptyStatement;
}
@@ -2603,8 +2659,9 @@ namespace ts {
AfterFinally = 1 << 13, // Injected edge that links post-finally flow with the rest of the graph
/** @internal */
Cached = 1 << 14, // Indicates that at least one cross-call cache entry exists for this node, even if not a loop participant
Label = BranchLabel | LoopLabel,
Condition = TrueCondition | FalseCondition
Condition = TrueCondition | FalseCondition,
}
export type FlowNode =
@@ -3209,6 +3266,8 @@ namespace ts {
/* @internal */ getParameterType(signature: Signature, parameterIndex: number): Type;
getNullableType(type: Type, flags: TypeFlags): Type;
getNonNullableType(type: Type): Type;
/* @internal */ getNonOptionalType(type: Type): Type;
/* @internal */ isNullableType(type: Type): boolean;
getTypeArguments(type: TypeReference): readonly Type[];
// TODO: GH#18217 `xToDeclaration` calls are frequently asserted as defined.
@@ -3329,6 +3388,7 @@ namespace ts {
/* @internal */ getNullType(): Type;
/* @internal */ getESSymbolType(): Type;
/* @internal */ getNeverType(): Type;
/* @internal */ getOptionalType(): Type;
/* @internal */ getUnionType(types: Type[], subtypeReduction?: UnionReduction): Type;
/* @internal */ createArrayType(elementType: Type): Type;
/* @internal */ getElementTypeOfArrayType(arrayType: Type): Type | undefined;
@@ -4590,6 +4650,8 @@ namespace ts {
isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison
/* @internal */
instantiations?: Map<Signature>; // Generic signature instantiation cache
/* @internal */
isOptionalCall?: boolean;
}
export const enum IndexKind {
@@ -6032,6 +6094,8 @@ namespace ts {
getColumn(): number;
getIndent(): number;
isAtStartOfLine(): boolean;
hasTrailingComment(): boolean;
hasTrailingWhitespace(): boolean;
getTextPosWithWriteLine?(): number;
}
+52 -3
View File
@@ -57,7 +57,6 @@ namespace ts {
function createSingleLineStringWriter(): EmitTextWriter {
let str = "";
const writeText: (text: string) => void = text => str += text;
return {
getText: () => str,
@@ -79,6 +78,8 @@ namespace ts {
getColumn: () => 0,
getIndent: () => 0,
isAtStartOfLine: () => false,
hasTrailingComment: () => false,
hasTrailingWhitespace: () => !!str.length && isWhiteSpaceLike(str.charCodeAt(str.length - 1)),
// Completely ignore indentation for string writers. And map newlines to
// a single space.
@@ -3349,6 +3350,7 @@ namespace ts {
let lineStart: boolean;
let lineCount: number;
let linePos: number;
let hasTrailingComment = false;
function updateLineCountAndPosFor(s: string) {
const lineStartsOfS = computeLineStarts(s);
@@ -3362,7 +3364,7 @@ namespace ts {
}
}
function write(s: string) {
function writeText(s: string) {
if (s && s.length) {
if (lineStart) {
s = getIndentString(indent) + s;
@@ -3373,18 +3375,30 @@ namespace ts {
}
}
function write(s: string) {
if (s) hasTrailingComment = false;
writeText(s);
}
function writeComment(s: string) {
if (s) hasTrailingComment = true;
writeText(s);
}
function reset(): void {
output = "";
indent = 0;
lineStart = true;
lineCount = 0;
linePos = 0;
hasTrailingComment = false;
}
function rawWrite(s: string) {
if (s !== undefined) {
output += s;
updateLineCountAndPosFor(s);
hasTrailingComment = false;
}
}
@@ -3400,6 +3414,7 @@ namespace ts {
lineCount++;
linePos = output.length;
lineStart = true;
hasTrailingComment = false;
}
}
@@ -3422,6 +3437,8 @@ namespace ts {
getColumn: () => lineStart ? indent * getIndentSize() : output.length - linePos,
getText: () => output,
isAtStartOfLine: () => lineStart,
hasTrailingComment: () => hasTrailingComment,
hasTrailingWhitespace: () => !!output.length && isWhiteSpaceLike(output.charCodeAt(output.length - 1)),
clear: reset,
reportInaccessibleThisError: noop,
reportPrivateInBaseOfClassExpression: noop,
@@ -3436,7 +3453,7 @@ namespace ts {
writeStringLiteral: write,
writeSymbol: (s, _) => write(s),
writeTrailingSemicolon: write,
writeComment: write,
writeComment,
getTextPosWithWriteLine
};
}
@@ -4792,6 +4809,10 @@ namespace ts {
return false;
}
}
export function getDotOrQuestionDotToken(node: PropertyAccessExpression) {
return node.questionDotToken || createNode(SyntaxKind.DotToken, node.expression.end, node.name.pos) as DotToken;
}
}
namespace ts {
@@ -5807,14 +5828,32 @@ namespace ts {
return node.kind === SyntaxKind.PropertyAccessExpression;
}
export function isPropertyAccessChain(node: Node): node is PropertyAccessChain {
return isPropertyAccessExpression(node) && !!(node.flags & NodeFlags.OptionalChain);
}
export function isElementAccessExpression(node: Node): node is ElementAccessExpression {
return node.kind === SyntaxKind.ElementAccessExpression;
}
export function isElementAccessChain(node: Node): node is ElementAccessChain {
return isElementAccessExpression(node) && !!(node.flags & NodeFlags.OptionalChain);
}
export function isCallExpression(node: Node): node is CallExpression {
return node.kind === SyntaxKind.CallExpression;
}
export function isCallChain(node: Node): node is CallChain {
return isCallExpression(node) && !!(node.flags & NodeFlags.OptionalChain);
}
export function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain {
return isPropertyAccessChain(node)
|| isElementAccessChain(node)
|| isCallChain(node);
}
export function isNewExpression(node: Node): node is NewExpression {
return node.kind === SyntaxKind.NewExpression;
}
@@ -6823,6 +6862,11 @@ namespace ts {
return node.kind === SyntaxKind.NotEmittedStatement;
}
/* @internal */
export function isSyntheticReference(node: Node): node is SyntheticReferenceExpression {
return node.kind === SyntaxKind.SyntheticReferenceExpression;
}
/* @internal */
export function isNotEmittedOrPartiallyEmittedNode(node: Node): node is NotEmittedStatement | PartiallyEmittedExpression {
return isNotEmittedStatement(node)
@@ -7127,6 +7171,11 @@ namespace ts {
return node.kind === SyntaxKind.GetAccessor;
}
/* @internal */
export function isOptionalChainRoot(node: Node): node is OptionalChainRoot {
return isOptionalChain(node) && !!node.questionDotToken;
}
/** True if has jsdoc nodes attached to it. */
/* @internal */
// TODO: GH#19856 Would like to return `node is Node & { jsDoc: JSDoc[] }` but it causes long compile times
+19
View File
@@ -456,16 +456,35 @@ namespace ts {
nodesVisitor((<ObjectLiteralExpression>node).properties, visitor, isObjectLiteralElementLike));
case SyntaxKind.PropertyAccessExpression:
if (node.flags & NodeFlags.OptionalChain) {
return updatePropertyAccessChain(<PropertyAccessChain>node,
visitNode((<PropertyAccessChain>node).expression, visitor, isExpression),
visitNode((<PropertyAccessChain>node).questionDotToken, visitor, isToken),
visitNode((<PropertyAccessChain>node).name, visitor, isIdentifier));
}
return updatePropertyAccess(<PropertyAccessExpression>node,
visitNode((<PropertyAccessExpression>node).expression, visitor, isExpression),
visitNode((<PropertyAccessExpression>node).name, visitor, isIdentifier));
case SyntaxKind.ElementAccessExpression:
if (node.flags & NodeFlags.OptionalChain) {
return updateElementAccessChain(<ElementAccessChain>node,
visitNode((<ElementAccessChain>node).expression, visitor, isExpression),
visitNode((<ElementAccessChain>node).questionDotToken, visitor, isToken),
visitNode((<ElementAccessChain>node).argumentExpression, visitor, isExpression));
}
return updateElementAccess(<ElementAccessExpression>node,
visitNode((<ElementAccessExpression>node).expression, visitor, isExpression),
visitNode((<ElementAccessExpression>node).argumentExpression, visitor, isExpression));
case SyntaxKind.CallExpression:
if (node.flags & NodeFlags.OptionalChain) {
return updateCallChain(<CallChain>node,
visitNode((<CallChain>node).expression, visitor, isExpression),
visitNode((<CallChain>node).questionDotToken, visitor, isToken),
nodesVisitor((<CallChain>node).typeArguments, visitor, isTypeNode),
nodesVisitor((<CallChain>node).arguments, visitor, isExpression));
}
return updateCall(<CallExpression>node,
visitNode((<CallExpression>node).expression, visitor, isExpression),
nodesVisitor((<CallExpression>node).typeArguments, visitor, isTypeNode),
+93 -29
View File
@@ -11,28 +11,52 @@ namespace ts.Completions {
}
export type Log = (message: string) => void;
const enum SymbolOriginInfoKind { ThisType, SymbolMemberNoExport, SymbolMemberExport, Export, Promise }
type SymbolOriginInfo = { kind: SymbolOriginInfoKind.ThisType } | { kind: SymbolOriginInfoKind.Promise } | { kind: SymbolOriginInfoKind.SymbolMemberNoExport } | SymbolOriginInfoExport;
interface SymbolOriginInfoExport {
kind: SymbolOriginInfoKind.SymbolMemberExport | SymbolOriginInfoKind.Export;
const enum SymbolOriginInfoKind {
ThisType = 1 << 0,
SymbolMember = 1 << 1,
Export = 1 << 2,
Promise = 1 << 3,
Nullable = 1 << 4,
SymbolMemberNoExport = SymbolMember,
SymbolMemberExport = SymbolMember | Export,
}
interface SymbolOriginInfo {
kind: SymbolOriginInfoKind;
}
interface SymbolOriginInfoExport extends SymbolOriginInfo {
kind: SymbolOriginInfoKind;
moduleSymbol: Symbol;
isDefaultExport: boolean;
}
function originIsThisType(origin: SymbolOriginInfo): boolean {
return !!(origin.kind & SymbolOriginInfoKind.ThisType);
}
function originIsSymbolMember(origin: SymbolOriginInfo): boolean {
return origin.kind === SymbolOriginInfoKind.SymbolMemberExport || origin.kind === SymbolOriginInfoKind.SymbolMemberNoExport;
return !!(origin.kind & SymbolOriginInfoKind.SymbolMember);
}
function originIsExport(origin: SymbolOriginInfo): origin is SymbolOriginInfoExport {
return origin.kind === SymbolOriginInfoKind.SymbolMemberExport || origin.kind === SymbolOriginInfoKind.Export;
return !!(origin.kind & SymbolOriginInfoKind.Export);
}
function originIsPromise(origin: SymbolOriginInfo): boolean {
return origin.kind === SymbolOriginInfoKind.Promise;
return !!(origin.kind & SymbolOriginInfoKind.Promise);
}
function originIsNullableMember(origin: SymbolOriginInfo): boolean {
return !!(origin.kind & SymbolOriginInfoKind.Nullable);
}
/**
* Map from symbol id -> SymbolOriginInfo.
* Only populated for symbols that come from other modules.
*/
type SymbolOriginInfoMap = (SymbolOriginInfo | undefined)[];
type SymbolOriginInfoMap = (SymbolOriginInfo | SymbolOriginInfoExport | undefined)[];
type SymbolSortTextMap = (SortText | undefined)[];
@@ -314,14 +338,26 @@ namespace ts.Completions {
): CompletionEntry | undefined {
let insertText: string | undefined;
let replacementSpan: TextSpan | undefined;
if (origin && origin.kind === SymbolOriginInfoKind.ThisType) {
insertText = needsConvertPropertyAccess ? `this[${quote(name, preferences)}]` : `this.${name}`;
const insertQuestionDot = origin && originIsNullableMember(origin);
const useBraces = origin && originIsSymbolMember(origin) || needsConvertPropertyAccess;
if (origin && originIsThisType(origin)) {
insertText = needsConvertPropertyAccess
? `this${insertQuestionDot ? "?." : ""}[${quote(name, preferences)}]`
: `this${insertQuestionDot ? "?." : "."}${name}`;
}
// We should only have needsConvertPropertyAccess if there's a property access to convert. But see #21790.
// Somehow there was a global with a non-identifier name. Hopefully someone will complain about getting a "foo bar" global completion and provide a repro.
else if ((origin && originIsSymbolMember(origin) || needsConvertPropertyAccess) && propertyAccessToConvert) {
insertText = needsConvertPropertyAccess ? `[${quote(name, preferences)}]` : `[${name}]`;
const dot = findChildOfKind(propertyAccessToConvert, SyntaxKind.DotToken, sourceFile)!;
else if ((useBraces || insertQuestionDot) && propertyAccessToConvert) {
insertText = useBraces ? needsConvertPropertyAccess ? `[${quote(name, preferences)}]` : `[${name}]` : name;
if (insertQuestionDot || propertyAccessToConvert.questionDotToken) {
insertText = `?.${insertText}`;
}
const dot = findChildOfKind(propertyAccessToConvert, SyntaxKind.DotToken, sourceFile) ||
findChildOfKind(propertyAccessToConvert, SyntaxKind.QuestionDotToken, sourceFile);
if (!dot) {
return undefined;
}
// If the text after the '.' starts with this name, write over it. Else, add new text.
const end = startsWith(name, propertyAccessToConvert.name.text) ? propertyAccessToConvert.name.end : dot.end;
replacementSpan = createTextSpanFromBounds(dot.getStart(sourceFile), end);
@@ -337,7 +373,7 @@ namespace ts.Completions {
if (origin && originIsPromise(origin) && propertyAccessToConvert) {
if (insertText === undefined) insertText = name;
const awaitText = `(await ${propertyAccessToConvert.expression.getText()})`;
insertText = needsConvertPropertyAccess ? `${awaitText}${insertText}` : `${awaitText}.${insertText}`;
insertText = needsConvertPropertyAccess ? `${awaitText}${insertText}` : `${awaitText}${insertQuestionDot ? "?." : "."}${insertText}`;
replacementSpan = createTextSpanFromBounds(propertyAccessToConvert.getStart(sourceFile), propertyAccessToConvert.end);
}
@@ -846,6 +882,7 @@ namespace ts.Completions {
let node = currentToken;
let propertyAccessToConvert: PropertyAccessExpression | undefined;
let isRightOfDot = false;
let isRightOfQuestionDot = false;
let isRightOfOpenTag = false;
let isStartingCloseTag = false;
let isJsxInitializer: IsJsxInitializer = false;
@@ -859,8 +896,9 @@ namespace ts.Completions {
}
let parent = contextToken.parent;
if (contextToken.kind === SyntaxKind.DotToken) {
isRightOfDot = true;
if (contextToken.kind === SyntaxKind.DotToken || contextToken.kind === SyntaxKind.QuestionDotToken) {
isRightOfDot = contextToken.kind === SyntaxKind.DotToken;
isRightOfQuestionDot = contextToken.kind === SyntaxKind.QuestionDotToken;
switch (parent.kind) {
case SyntaxKind.PropertyAccessExpression:
propertyAccessToConvert = parent as PropertyAccessExpression;
@@ -967,7 +1005,7 @@ namespace ts.Completions {
const symbolToSortTextMap: SymbolSortTextMap = [];
const importSuggestionsCache = host.getImportSuggestionsCache && host.getImportSuggestionsCache();
if (isRightOfDot) {
if (isRightOfDot || isRightOfQuestionDot) {
getTypeScriptMemberSymbols();
}
else if (isRightOfOpenTag) {
@@ -1074,7 +1112,13 @@ namespace ts.Completions {
if (!isTypeLocation &&
symbol.declarations &&
symbol.declarations.some(d => d.kind !== SyntaxKind.SourceFile && d.kind !== SyntaxKind.ModuleDeclaration && d.kind !== SyntaxKind.EnumDeclaration)) {
addTypeProperties(typeChecker.getTypeOfSymbolAtLocation(symbol, node), !!(node.flags & NodeFlags.AwaitContext));
let type = typeChecker.getTypeOfSymbolAtLocation(symbol, node).getNonOptionalType();
let insertQuestionDot = false;
if (type.isNullableType()) {
insertQuestionDot = isRightOfDot && !isRightOfQuestionDot;
type = type.getNonNullableType();
}
addTypeProperties(type, !!(node.flags & NodeFlags.AwaitContext), insertQuestionDot);
}
return;
@@ -1089,12 +1133,21 @@ namespace ts.Completions {
}
if (!isTypeLocation) {
addTypeProperties(typeChecker.getTypeAtLocation(node), !!(node.flags & NodeFlags.AwaitContext));
let type = typeChecker.getTypeAtLocation(node).getNonOptionalType();
let insertQuestionDot = false;
if (type.isNullableType()) {
insertQuestionDot = isRightOfDot && !isRightOfQuestionDot;
type = type.getNonNullableType();
}
addTypeProperties(type, !!(node.flags & NodeFlags.AwaitContext), insertQuestionDot);
}
}
function addTypeProperties(type: Type, insertAwait?: boolean): void {
function addTypeProperties(type: Type, insertAwait: boolean, insertQuestionDot: boolean): void {
isNewIdentifierLocation = !!type.getStringIndexType();
if (isRightOfQuestionDot && some(type.getCallSignatures())) {
isNewIdentifierLocation = true;
}
const propertyAccess = node.kind === SyntaxKind.ImportType ? <ImportTypeNode>node : <PropertyAccessExpression | QualifiedName>node.parent;
if (isUncheckedFile) {
@@ -1108,7 +1161,7 @@ namespace ts.Completions {
else {
for (const symbol of type.getApparentProperties()) {
if (typeChecker.isValidPropertyAccessForCompletions(propertyAccess, type, symbol)) {
addPropertySymbol(symbol);
addPropertySymbol(symbol, /*insertAwait*/ false, insertQuestionDot);
}
}
}
@@ -1118,14 +1171,14 @@ namespace ts.Completions {
if (promiseType) {
for (const symbol of promiseType.getApparentProperties()) {
if (typeChecker.isValidPropertyAccessForCompletions(propertyAccess, promiseType, symbol)) {
addPropertySymbol(symbol, /* insertAwait */ true);
addPropertySymbol(symbol, /* insertAwait */ true, insertQuestionDot);
}
}
}
}
}
function addPropertySymbol(symbol: Symbol, insertAwait?: boolean) {
function addPropertySymbol(symbol: Symbol, insertAwait: boolean, insertQuestionDot: boolean) {
// For a computed property with an accessible name like `Symbol.iterator`,
// we'll add a completion for the *name* `Symbol` instead of for the property.
// If this is e.g. [Symbol.iterator], add a completion for `Symbol`.
@@ -1139,23 +1192,34 @@ namespace ts.Completions {
symbols.push(firstAccessibleSymbol);
const moduleSymbol = firstAccessibleSymbol.parent;
symbolToOriginInfoMap[getSymbolId(firstAccessibleSymbol)] =
!moduleSymbol || !isExternalModuleSymbol(moduleSymbol) ? { kind: SymbolOriginInfoKind.SymbolMemberNoExport } : { kind: SymbolOriginInfoKind.SymbolMemberExport, moduleSymbol, isDefaultExport: false };
!moduleSymbol || !isExternalModuleSymbol(moduleSymbol)
? { kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.SymbolMemberNoExport) }
: { kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.SymbolMemberExport), moduleSymbol, isDefaultExport: false };
}
else if (preferences.includeCompletionsWithInsertText) {
addPromiseSymbolOriginInfo(symbol);
addSymbolOriginInfo(symbol);
symbols.push(symbol);
}
}
else {
addPromiseSymbolOriginInfo(symbol);
addSymbolOriginInfo(symbol);
symbols.push(symbol);
}
function addPromiseSymbolOriginInfo (symbol: Symbol) {
if (insertAwait && preferences.includeCompletionsWithInsertText && !symbolToOriginInfoMap[getSymbolId(symbol)]) {
symbolToOriginInfoMap[getSymbolId(symbol)] = { kind: SymbolOriginInfoKind.Promise };
function addSymbolOriginInfo(symbol: Symbol) {
if (preferences.includeCompletionsWithInsertText) {
if (insertAwait && !symbolToOriginInfoMap[getSymbolId(symbol)]) {
symbolToOriginInfoMap[getSymbolId(symbol)] = { kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.Promise) };
}
else if (insertQuestionDot) {
symbolToOriginInfoMap[getSymbolId(symbol)] = { kind: SymbolOriginInfoKind.Nullable };
}
}
}
function getNullableSymbolOriginInfoKind(kind: SymbolOriginInfoKind) {
return insertQuestionDot ? kind | SymbolOriginInfoKind.Nullable : kind;
}
}
/** Given 'a.b.c', returns 'a'. */
+6
View File
@@ -409,9 +409,15 @@ namespace ts {
getBaseTypes(): BaseType[] | undefined {
return this.isClassOrInterface() ? this.checker.getBaseTypes(this) : undefined;
}
isNullableType(): boolean {
return this.checker.isNullableType(this);
}
getNonNullableType(): Type {
return this.checker.getNonNullableType(this);
}
getNonOptionalType(): Type {
return this.checker.getNonOptionalType(this);
}
getConstraint(): Type | undefined {
return this.checker.getBaseConstraintOfType(this);
}
+2
View File
@@ -1061,6 +1061,8 @@ namespace ts.textChanges {
getColumn,
getIndent,
isAtStartOfLine,
hasTrailingComment: () => writer.hasTrailingComment(),
hasTrailingWhitespace: () => writer.hasTrailingWhitespace(),
clear
};
}
+2
View File
@@ -52,6 +52,8 @@ namespace ts {
getNumberIndexType(): Type | undefined;
getBaseTypes(): BaseType[] | undefined;
getNonNullableType(): Type;
/*@internal*/ getNonOptionalType(): Type;
/*@internal*/ isNullableType(): boolean;
getConstraint(): Type | undefined;
getDefault(): Type | undefined;
+16 -1
View File
@@ -956,6 +956,12 @@ namespace ts {
}
}
export function removeOptionality(type: Type, isOptionalExpression: boolean, isOptionalChain: boolean) {
return isOptionalExpression ? type.getNonNullableType() :
isOptionalChain ? type.getNonOptionalType() :
type;
}
export function isPossiblyTypeArgumentPosition(token: Node, sourceFile: SourceFile, checker: TypeChecker): boolean {
const info = getPossibleTypeArgumentsInfo(token, sourceFile);
return info !== undefined && (isPartOfTypeNode(info.called) ||
@@ -964,7 +970,11 @@ namespace ts {
}
export function getPossibleGenericSignatures(called: Expression, typeArgumentCount: number, checker: TypeChecker): readonly Signature[] {
const type = checker.getTypeAtLocation(called);
let type = checker.getTypeAtLocation(called);
if (isOptionalChain(called.parent)) {
type = removeOptionality(type, !!called.parent.questionDotToken, /*isOptionalChain*/ true);
}
const signatures = isNewExpression(called.parent) ? type.getConstructSignatures() : type.getCallSignatures();
return signatures.filter(candidate => !!candidate.typeParameters && candidate.typeParameters.length >= typeArgumentCount);
}
@@ -993,6 +1003,9 @@ namespace ts {
case SyntaxKind.LessThanToken:
// Found the beginning of the generic argument expression
token = findPrecedingToken(token.getFullStart(), sourceFile);
if (token && token.kind === SyntaxKind.QuestionDotToken) {
token = findPrecedingToken(token.getFullStart(), sourceFile);
}
if (!token || !isIdentifier(token)) return undefined;
if (!remainingLessThanTokens) {
return isDeclarationName(token) ? undefined : { called: token, nTypeArguments };
@@ -1493,6 +1506,8 @@ namespace ts {
getColumn: () => 0,
getLine: () => 0,
isAtStartOfLine: () => false,
hasTrailingWhitespace: () => false,
hasTrailingComment: () => false,
rawWrite: notImplemented,
getIndent: () => indent,
increaseIndent: () => { indent++; },
+1
View File
@@ -76,6 +76,7 @@
"unittests/evaluation/awaiter.ts",
"unittests/evaluation/forAwaitOf.ts",
"unittests/evaluation/forOf.ts",
"unittests/evaluation/optionalCall.ts",
"unittests/evaluation/objectRest.ts",
"unittests/services/cancellableLanguageServiceOperations.ts",
"unittests/services/colorization.ts",
@@ -0,0 +1,191 @@
describe("unittests:: evaluation:: optionalCall", () => {
it("f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
function f(a) {
output.push(a);
output.push(this);
}
export const output: any[] = [];
f?.(1);
`);
assert.strictEqual(result.output[0], 1);
assert.isUndefined(result.output[1]);
});
it("o.f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
f(a) {
output.push(a);
output.push(this);
}
};
export const output: any[] = [];
o.f?.(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o);
});
it("o.x.f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
x: {
f(a) {
output.push(a);
output.push(this);
}
}
};
export const output: any[] = [];
o.x.f?.(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o.x);
});
it("o?.f()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
f(a) {
output.push(a);
output.push(this);
}
};
export const output: any[] = [];
o?.f(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o);
});
it("o?.f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
f(a) {
output.push(a);
output.push(this);
}
};
export const output: any[] = [];
o?.f?.(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o);
});
it("o.x?.f()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
x: {
f(a) {
output.push(a);
output.push(this);
}
}
};
export const output: any[] = [];
o.x?.f(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o.x);
});
it("o?.x.f()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
x: {
f(a) {
output.push(a);
output.push(this);
}
}
};
export const output: any[] = [];
o?.x.f(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o.x);
});
it("o?.x?.f()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
x: {
f(a) {
output.push(a);
output.push(this);
}
}
};
export const output: any[] = [];
o?.x?.f(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o.x);
});
it("o?.x?.f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
x: {
f(a) {
output.push(a);
output.push(this);
}
}
};
export const output: any[] = [];
o?.x?.f?.(1);
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], result.o.x);
});
it("f?.()?.()", async () => {
const result = evaluator.evaluateTypeScript(`
function g(a) {
output.push(a);
output.push(this);
}
function f(a) {
output.push(a);
return g;
}
export const output: any[] = [];
f?.(1)?.(2)
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], 2);
assert.isUndefined(result.output[2]);
});
it("f?.().f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
f(a) {
output.push(a);
output.push(this);
}
};
function f(a) {
output.push(a);
return o;
}
export const output: any[] = [];
f?.(1).f?.(2)
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], 2);
assert.strictEqual(result.output[2], result.o);
});
it("f?.()?.f?.()", async () => {
const result = evaluator.evaluateTypeScript(`
export const o = {
f(a) {
output.push(a);
output.push(this);
}
};
function f(a) {
output.push(a);
return o;
}
export const output: any[] = [];
f?.(1)?.f?.(2)
`);
assert.strictEqual(result.output[0], 1);
assert.strictEqual(result.output[1], 2);
assert.strictEqual(result.output[2], result.o);
});
});
+365 -337
View File
@@ -104,332 +104,334 @@ declare namespace ts {
DotDotDotToken = 25,
SemicolonToken = 26,
CommaToken = 27,
LessThanToken = 28,
LessThanSlashToken = 29,
GreaterThanToken = 30,
LessThanEqualsToken = 31,
GreaterThanEqualsToken = 32,
EqualsEqualsToken = 33,
ExclamationEqualsToken = 34,
EqualsEqualsEqualsToken = 35,
ExclamationEqualsEqualsToken = 36,
EqualsGreaterThanToken = 37,
PlusToken = 38,
MinusToken = 39,
AsteriskToken = 40,
AsteriskAsteriskToken = 41,
SlashToken = 42,
PercentToken = 43,
PlusPlusToken = 44,
MinusMinusToken = 45,
LessThanLessThanToken = 46,
GreaterThanGreaterThanToken = 47,
GreaterThanGreaterThanGreaterThanToken = 48,
AmpersandToken = 49,
BarToken = 50,
CaretToken = 51,
ExclamationToken = 52,
TildeToken = 53,
AmpersandAmpersandToken = 54,
BarBarToken = 55,
QuestionToken = 56,
ColonToken = 57,
AtToken = 58,
QuestionDotToken = 28,
LessThanToken = 29,
LessThanSlashToken = 30,
GreaterThanToken = 31,
LessThanEqualsToken = 32,
GreaterThanEqualsToken = 33,
EqualsEqualsToken = 34,
ExclamationEqualsToken = 35,
EqualsEqualsEqualsToken = 36,
ExclamationEqualsEqualsToken = 37,
EqualsGreaterThanToken = 38,
PlusToken = 39,
MinusToken = 40,
AsteriskToken = 41,
AsteriskAsteriskToken = 42,
SlashToken = 43,
PercentToken = 44,
PlusPlusToken = 45,
MinusMinusToken = 46,
LessThanLessThanToken = 47,
GreaterThanGreaterThanToken = 48,
GreaterThanGreaterThanGreaterThanToken = 49,
AmpersandToken = 50,
BarToken = 51,
CaretToken = 52,
ExclamationToken = 53,
TildeToken = 54,
AmpersandAmpersandToken = 55,
BarBarToken = 56,
QuestionToken = 57,
ColonToken = 58,
AtToken = 59,
/** Only the JSDoc scanner produces BacktickToken. The normal scanner produces NoSubstitutionTemplateLiteral and related kinds. */
BacktickToken = 59,
EqualsToken = 60,
PlusEqualsToken = 61,
MinusEqualsToken = 62,
AsteriskEqualsToken = 63,
AsteriskAsteriskEqualsToken = 64,
SlashEqualsToken = 65,
PercentEqualsToken = 66,
LessThanLessThanEqualsToken = 67,
GreaterThanGreaterThanEqualsToken = 68,
GreaterThanGreaterThanGreaterThanEqualsToken = 69,
AmpersandEqualsToken = 70,
BarEqualsToken = 71,
CaretEqualsToken = 72,
Identifier = 73,
BreakKeyword = 74,
CaseKeyword = 75,
CatchKeyword = 76,
ClassKeyword = 77,
ConstKeyword = 78,
ContinueKeyword = 79,
DebuggerKeyword = 80,
DefaultKeyword = 81,
DeleteKeyword = 82,
DoKeyword = 83,
ElseKeyword = 84,
EnumKeyword = 85,
ExportKeyword = 86,
ExtendsKeyword = 87,
FalseKeyword = 88,
FinallyKeyword = 89,
ForKeyword = 90,
FunctionKeyword = 91,
IfKeyword = 92,
ImportKeyword = 93,
InKeyword = 94,
InstanceOfKeyword = 95,
NewKeyword = 96,
NullKeyword = 97,
ReturnKeyword = 98,
SuperKeyword = 99,
SwitchKeyword = 100,
ThisKeyword = 101,
ThrowKeyword = 102,
TrueKeyword = 103,
TryKeyword = 104,
TypeOfKeyword = 105,
VarKeyword = 106,
VoidKeyword = 107,
WhileKeyword = 108,
WithKeyword = 109,
ImplementsKeyword = 110,
InterfaceKeyword = 111,
LetKeyword = 112,
PackageKeyword = 113,
PrivateKeyword = 114,
ProtectedKeyword = 115,
PublicKeyword = 116,
StaticKeyword = 117,
YieldKeyword = 118,
AbstractKeyword = 119,
AsKeyword = 120,
AssertsKeyword = 121,
AnyKeyword = 122,
AsyncKeyword = 123,
AwaitKeyword = 124,
BooleanKeyword = 125,
ConstructorKeyword = 126,
DeclareKeyword = 127,
GetKeyword = 128,
InferKeyword = 129,
IsKeyword = 130,
KeyOfKeyword = 131,
ModuleKeyword = 132,
NamespaceKeyword = 133,
NeverKeyword = 134,
ReadonlyKeyword = 135,
RequireKeyword = 136,
NumberKeyword = 137,
ObjectKeyword = 138,
SetKeyword = 139,
StringKeyword = 140,
SymbolKeyword = 141,
TypeKeyword = 142,
UndefinedKeyword = 143,
UniqueKeyword = 144,
UnknownKeyword = 145,
FromKeyword = 146,
GlobalKeyword = 147,
BigIntKeyword = 148,
OfKeyword = 149,
QualifiedName = 150,
ComputedPropertyName = 151,
TypeParameter = 152,
Parameter = 153,
Decorator = 154,
PropertySignature = 155,
PropertyDeclaration = 156,
MethodSignature = 157,
MethodDeclaration = 158,
Constructor = 159,
GetAccessor = 160,
SetAccessor = 161,
CallSignature = 162,
ConstructSignature = 163,
IndexSignature = 164,
TypePredicate = 165,
TypeReference = 166,
FunctionType = 167,
ConstructorType = 168,
TypeQuery = 169,
TypeLiteral = 170,
ArrayType = 171,
TupleType = 172,
OptionalType = 173,
RestType = 174,
UnionType = 175,
IntersectionType = 176,
ConditionalType = 177,
InferType = 178,
ParenthesizedType = 179,
ThisType = 180,
TypeOperator = 181,
IndexedAccessType = 182,
MappedType = 183,
LiteralType = 184,
ImportType = 185,
ObjectBindingPattern = 186,
ArrayBindingPattern = 187,
BindingElement = 188,
ArrayLiteralExpression = 189,
ObjectLiteralExpression = 190,
PropertyAccessExpression = 191,
ElementAccessExpression = 192,
CallExpression = 193,
NewExpression = 194,
TaggedTemplateExpression = 195,
TypeAssertionExpression = 196,
ParenthesizedExpression = 197,
FunctionExpression = 198,
ArrowFunction = 199,
DeleteExpression = 200,
TypeOfExpression = 201,
VoidExpression = 202,
AwaitExpression = 203,
PrefixUnaryExpression = 204,
PostfixUnaryExpression = 205,
BinaryExpression = 206,
ConditionalExpression = 207,
TemplateExpression = 208,
YieldExpression = 209,
SpreadElement = 210,
ClassExpression = 211,
OmittedExpression = 212,
ExpressionWithTypeArguments = 213,
AsExpression = 214,
NonNullExpression = 215,
MetaProperty = 216,
SyntheticExpression = 217,
TemplateSpan = 218,
SemicolonClassElement = 219,
Block = 220,
EmptyStatement = 221,
VariableStatement = 222,
ExpressionStatement = 223,
IfStatement = 224,
DoStatement = 225,
WhileStatement = 226,
ForStatement = 227,
ForInStatement = 228,
ForOfStatement = 229,
ContinueStatement = 230,
BreakStatement = 231,
ReturnStatement = 232,
WithStatement = 233,
SwitchStatement = 234,
LabeledStatement = 235,
ThrowStatement = 236,
TryStatement = 237,
DebuggerStatement = 238,
VariableDeclaration = 239,
VariableDeclarationList = 240,
FunctionDeclaration = 241,
ClassDeclaration = 242,
InterfaceDeclaration = 243,
TypeAliasDeclaration = 244,
EnumDeclaration = 245,
ModuleDeclaration = 246,
ModuleBlock = 247,
CaseBlock = 248,
NamespaceExportDeclaration = 249,
ImportEqualsDeclaration = 250,
ImportDeclaration = 251,
ImportClause = 252,
NamespaceImport = 253,
NamedImports = 254,
ImportSpecifier = 255,
ExportAssignment = 256,
ExportDeclaration = 257,
NamedExports = 258,
ExportSpecifier = 259,
MissingDeclaration = 260,
ExternalModuleReference = 261,
JsxElement = 262,
JsxSelfClosingElement = 263,
JsxOpeningElement = 264,
JsxClosingElement = 265,
JsxFragment = 266,
JsxOpeningFragment = 267,
JsxClosingFragment = 268,
JsxAttribute = 269,
JsxAttributes = 270,
JsxSpreadAttribute = 271,
JsxExpression = 272,
CaseClause = 273,
DefaultClause = 274,
HeritageClause = 275,
CatchClause = 276,
PropertyAssignment = 277,
ShorthandPropertyAssignment = 278,
SpreadAssignment = 279,
EnumMember = 280,
UnparsedPrologue = 281,
UnparsedPrepend = 282,
UnparsedText = 283,
UnparsedInternalText = 284,
UnparsedSyntheticReference = 285,
SourceFile = 286,
Bundle = 287,
UnparsedSource = 288,
InputFiles = 289,
JSDocTypeExpression = 290,
JSDocAllType = 291,
JSDocUnknownType = 292,
JSDocNullableType = 293,
JSDocNonNullableType = 294,
JSDocOptionalType = 295,
JSDocFunctionType = 296,
JSDocVariadicType = 297,
JSDocNamepathType = 298,
JSDocComment = 299,
JSDocTypeLiteral = 300,
JSDocSignature = 301,
JSDocTag = 302,
JSDocAugmentsTag = 303,
JSDocAuthorTag = 304,
JSDocClassTag = 305,
JSDocCallbackTag = 306,
JSDocEnumTag = 307,
JSDocParameterTag = 308,
JSDocReturnTag = 309,
JSDocThisTag = 310,
JSDocTypeTag = 311,
JSDocTemplateTag = 312,
JSDocTypedefTag = 313,
JSDocPropertyTag = 314,
SyntaxList = 315,
NotEmittedStatement = 316,
PartiallyEmittedExpression = 317,
CommaListExpression = 318,
MergeDeclarationMarker = 319,
EndOfDeclarationMarker = 320,
Count = 321,
FirstAssignment = 60,
LastAssignment = 72,
FirstCompoundAssignment = 61,
LastCompoundAssignment = 72,
FirstReservedWord = 74,
LastReservedWord = 109,
FirstKeyword = 74,
LastKeyword = 149,
FirstFutureReservedWord = 110,
LastFutureReservedWord = 118,
FirstTypeNode = 165,
LastTypeNode = 185,
BacktickToken = 60,
EqualsToken = 61,
PlusEqualsToken = 62,
MinusEqualsToken = 63,
AsteriskEqualsToken = 64,
AsteriskAsteriskEqualsToken = 65,
SlashEqualsToken = 66,
PercentEqualsToken = 67,
LessThanLessThanEqualsToken = 68,
GreaterThanGreaterThanEqualsToken = 69,
GreaterThanGreaterThanGreaterThanEqualsToken = 70,
AmpersandEqualsToken = 71,
BarEqualsToken = 72,
CaretEqualsToken = 73,
Identifier = 74,
BreakKeyword = 75,
CaseKeyword = 76,
CatchKeyword = 77,
ClassKeyword = 78,
ConstKeyword = 79,
ContinueKeyword = 80,
DebuggerKeyword = 81,
DefaultKeyword = 82,
DeleteKeyword = 83,
DoKeyword = 84,
ElseKeyword = 85,
EnumKeyword = 86,
ExportKeyword = 87,
ExtendsKeyword = 88,
FalseKeyword = 89,
FinallyKeyword = 90,
ForKeyword = 91,
FunctionKeyword = 92,
IfKeyword = 93,
ImportKeyword = 94,
InKeyword = 95,
InstanceOfKeyword = 96,
NewKeyword = 97,
NullKeyword = 98,
ReturnKeyword = 99,
SuperKeyword = 100,
SwitchKeyword = 101,
ThisKeyword = 102,
ThrowKeyword = 103,
TrueKeyword = 104,
TryKeyword = 105,
TypeOfKeyword = 106,
VarKeyword = 107,
VoidKeyword = 108,
WhileKeyword = 109,
WithKeyword = 110,
ImplementsKeyword = 111,
InterfaceKeyword = 112,
LetKeyword = 113,
PackageKeyword = 114,
PrivateKeyword = 115,
ProtectedKeyword = 116,
PublicKeyword = 117,
StaticKeyword = 118,
YieldKeyword = 119,
AbstractKeyword = 120,
AsKeyword = 121,
AssertsKeyword = 122,
AnyKeyword = 123,
AsyncKeyword = 124,
AwaitKeyword = 125,
BooleanKeyword = 126,
ConstructorKeyword = 127,
DeclareKeyword = 128,
GetKeyword = 129,
InferKeyword = 130,
IsKeyword = 131,
KeyOfKeyword = 132,
ModuleKeyword = 133,
NamespaceKeyword = 134,
NeverKeyword = 135,
ReadonlyKeyword = 136,
RequireKeyword = 137,
NumberKeyword = 138,
ObjectKeyword = 139,
SetKeyword = 140,
StringKeyword = 141,
SymbolKeyword = 142,
TypeKeyword = 143,
UndefinedKeyword = 144,
UniqueKeyword = 145,
UnknownKeyword = 146,
FromKeyword = 147,
GlobalKeyword = 148,
BigIntKeyword = 149,
OfKeyword = 150,
QualifiedName = 151,
ComputedPropertyName = 152,
TypeParameter = 153,
Parameter = 154,
Decorator = 155,
PropertySignature = 156,
PropertyDeclaration = 157,
MethodSignature = 158,
MethodDeclaration = 159,
Constructor = 160,
GetAccessor = 161,
SetAccessor = 162,
CallSignature = 163,
ConstructSignature = 164,
IndexSignature = 165,
TypePredicate = 166,
TypeReference = 167,
FunctionType = 168,
ConstructorType = 169,
TypeQuery = 170,
TypeLiteral = 171,
ArrayType = 172,
TupleType = 173,
OptionalType = 174,
RestType = 175,
UnionType = 176,
IntersectionType = 177,
ConditionalType = 178,
InferType = 179,
ParenthesizedType = 180,
ThisType = 181,
TypeOperator = 182,
IndexedAccessType = 183,
MappedType = 184,
LiteralType = 185,
ImportType = 186,
ObjectBindingPattern = 187,
ArrayBindingPattern = 188,
BindingElement = 189,
ArrayLiteralExpression = 190,
ObjectLiteralExpression = 191,
PropertyAccessExpression = 192,
ElementAccessExpression = 193,
CallExpression = 194,
NewExpression = 195,
TaggedTemplateExpression = 196,
TypeAssertionExpression = 197,
ParenthesizedExpression = 198,
FunctionExpression = 199,
ArrowFunction = 200,
DeleteExpression = 201,
TypeOfExpression = 202,
VoidExpression = 203,
AwaitExpression = 204,
PrefixUnaryExpression = 205,
PostfixUnaryExpression = 206,
BinaryExpression = 207,
ConditionalExpression = 208,
TemplateExpression = 209,
YieldExpression = 210,
SpreadElement = 211,
ClassExpression = 212,
OmittedExpression = 213,
ExpressionWithTypeArguments = 214,
AsExpression = 215,
NonNullExpression = 216,
MetaProperty = 217,
SyntheticExpression = 218,
TemplateSpan = 219,
SemicolonClassElement = 220,
Block = 221,
EmptyStatement = 222,
VariableStatement = 223,
ExpressionStatement = 224,
IfStatement = 225,
DoStatement = 226,
WhileStatement = 227,
ForStatement = 228,
ForInStatement = 229,
ForOfStatement = 230,
ContinueStatement = 231,
BreakStatement = 232,
ReturnStatement = 233,
WithStatement = 234,
SwitchStatement = 235,
LabeledStatement = 236,
ThrowStatement = 237,
TryStatement = 238,
DebuggerStatement = 239,
VariableDeclaration = 240,
VariableDeclarationList = 241,
FunctionDeclaration = 242,
ClassDeclaration = 243,
InterfaceDeclaration = 244,
TypeAliasDeclaration = 245,
EnumDeclaration = 246,
ModuleDeclaration = 247,
ModuleBlock = 248,
CaseBlock = 249,
NamespaceExportDeclaration = 250,
ImportEqualsDeclaration = 251,
ImportDeclaration = 252,
ImportClause = 253,
NamespaceImport = 254,
NamedImports = 255,
ImportSpecifier = 256,
ExportAssignment = 257,
ExportDeclaration = 258,
NamedExports = 259,
ExportSpecifier = 260,
MissingDeclaration = 261,
ExternalModuleReference = 262,
JsxElement = 263,
JsxSelfClosingElement = 264,
JsxOpeningElement = 265,
JsxClosingElement = 266,
JsxFragment = 267,
JsxOpeningFragment = 268,
JsxClosingFragment = 269,
JsxAttribute = 270,
JsxAttributes = 271,
JsxSpreadAttribute = 272,
JsxExpression = 273,
CaseClause = 274,
DefaultClause = 275,
HeritageClause = 276,
CatchClause = 277,
PropertyAssignment = 278,
ShorthandPropertyAssignment = 279,
SpreadAssignment = 280,
EnumMember = 281,
UnparsedPrologue = 282,
UnparsedPrepend = 283,
UnparsedText = 284,
UnparsedInternalText = 285,
UnparsedSyntheticReference = 286,
SourceFile = 287,
Bundle = 288,
UnparsedSource = 289,
InputFiles = 290,
JSDocTypeExpression = 291,
JSDocAllType = 292,
JSDocUnknownType = 293,
JSDocNullableType = 294,
JSDocNonNullableType = 295,
JSDocOptionalType = 296,
JSDocFunctionType = 297,
JSDocVariadicType = 298,
JSDocNamepathType = 299,
JSDocComment = 300,
JSDocTypeLiteral = 301,
JSDocSignature = 302,
JSDocTag = 303,
JSDocAugmentsTag = 304,
JSDocAuthorTag = 305,
JSDocClassTag = 306,
JSDocCallbackTag = 307,
JSDocEnumTag = 308,
JSDocParameterTag = 309,
JSDocReturnTag = 310,
JSDocThisTag = 311,
JSDocTypeTag = 312,
JSDocTemplateTag = 313,
JSDocTypedefTag = 314,
JSDocPropertyTag = 315,
SyntaxList = 316,
NotEmittedStatement = 317,
PartiallyEmittedExpression = 318,
CommaListExpression = 319,
MergeDeclarationMarker = 320,
EndOfDeclarationMarker = 321,
SyntheticReferenceExpression = 322,
Count = 323,
FirstAssignment = 61,
LastAssignment = 73,
FirstCompoundAssignment = 62,
LastCompoundAssignment = 73,
FirstReservedWord = 75,
LastReservedWord = 110,
FirstKeyword = 75,
LastKeyword = 150,
FirstFutureReservedWord = 111,
LastFutureReservedWord = 119,
FirstTypeNode = 166,
LastTypeNode = 186,
FirstPunctuation = 18,
LastPunctuation = 72,
LastPunctuation = 73,
FirstToken = 0,
LastToken = 149,
LastToken = 150,
FirstTriviaToken = 2,
LastTriviaToken = 7,
FirstLiteralToken = 8,
LastLiteralToken = 14,
FirstTemplateToken = 14,
LastTemplateToken = 17,
FirstBinaryOperator = 28,
LastBinaryOperator = 72,
FirstStatement = 222,
LastStatement = 238,
FirstNode = 150,
FirstJSDocNode = 290,
LastJSDocNode = 314,
FirstJSDocTagNode = 302,
LastJSDocTagNode = 314,
FirstBinaryOperator = 29,
LastBinaryOperator = 73,
FirstStatement = 223,
LastStatement = 239,
FirstNode = 151,
FirstJSDocNode = 291,
LastJSDocNode = 315,
FirstJSDocTagNode = 303,
LastJSDocTagNode = 315,
}
export enum NodeFlags {
None = 0,
@@ -438,27 +440,28 @@ declare namespace ts {
NestedNamespace = 4,
Synthesized = 8,
Namespace = 16,
ExportContext = 32,
ContainsThis = 64,
HasImplicitReturn = 128,
HasExplicitReturn = 256,
GlobalAugmentation = 512,
HasAsyncFunctions = 1024,
DisallowInContext = 2048,
YieldContext = 4096,
DecoratorContext = 8192,
AwaitContext = 16384,
ThisNodeHasError = 32768,
JavaScriptFile = 65536,
ThisNodeOrAnySubNodesHasError = 131072,
HasAggregatedChildData = 262144,
JSDoc = 2097152,
JsonFile = 16777216,
OptionalChain = 32,
ExportContext = 64,
ContainsThis = 128,
HasImplicitReturn = 256,
HasExplicitReturn = 512,
GlobalAugmentation = 1024,
HasAsyncFunctions = 2048,
DisallowInContext = 4096,
YieldContext = 8192,
DecoratorContext = 16384,
AwaitContext = 32768,
ThisNodeHasError = 65536,
JavaScriptFile = 131072,
ThisNodeOrAnySubNodesHasError = 262144,
HasAggregatedChildData = 524288,
JSDoc = 4194304,
JsonFile = 33554432,
BlockScoped = 3,
ReachabilityCheckFlags = 384,
ReachabilityAndEmitFlags = 1408,
ContextFlags = 12679168,
TypeExcludesFlags = 20480,
ReachabilityCheckFlags = 768,
ReachabilityAndEmitFlags = 2816,
ContextFlags = 25358336,
TypeExcludesFlags = 40960,
}
export enum ModifierFlags {
None = 0,
@@ -508,8 +511,10 @@ declare namespace ts {
export interface Token<TKind extends SyntaxKind> extends Node {
kind: TKind;
}
export type DotToken = Token<SyntaxKind.DotToken>;
export type DotDotDotToken = Token<SyntaxKind.DotDotDotToken>;
export type QuestionToken = Token<SyntaxKind.QuestionToken>;
export type QuestionDotToken = Token<SyntaxKind.QuestionDotToken>;
export type ExclamationToken = Token<SyntaxKind.ExclamationToken>;
export type ColonToken = Token<SyntaxKind.ColonToken>;
export type EqualsToken = Token<SyntaxKind.EqualsToken>;
@@ -1082,8 +1087,12 @@ declare namespace ts {
export interface PropertyAccessExpression extends MemberExpression, NamedDeclaration {
kind: SyntaxKind.PropertyAccessExpression;
expression: LeftHandSideExpression;
questionDotToken?: QuestionDotToken;
name: Identifier;
}
export interface PropertyAccessChain extends PropertyAccessExpression {
_optionalChainBrand: any;
}
export interface SuperPropertyAccessExpression extends PropertyAccessExpression {
expression: SuperExpression;
}
@@ -1095,8 +1104,12 @@ declare namespace ts {
export interface ElementAccessExpression extends MemberExpression {
kind: SyntaxKind.ElementAccessExpression;
expression: LeftHandSideExpression;
questionDotToken?: QuestionDotToken;
argumentExpression: Expression;
}
export interface ElementAccessChain extends ElementAccessExpression {
_optionalChainBrand: any;
}
export interface SuperElementAccessExpression extends ElementAccessExpression {
expression: SuperExpression;
}
@@ -1104,9 +1117,14 @@ declare namespace ts {
export interface CallExpression extends LeftHandSideExpression, Declaration {
kind: SyntaxKind.CallExpression;
expression: LeftHandSideExpression;
questionDotToken?: QuestionDotToken;
typeArguments?: NodeArray<TypeNode>;
arguments: NodeArray<Expression>;
}
export interface CallChain extends CallExpression {
_optionalChainBrand: any;
}
export type OptionalChain = PropertyAccessChain | ElementAccessChain | CallChain;
export interface SuperCall extends CallExpression {
expression: SuperExpression;
}
@@ -3496,8 +3514,12 @@ declare namespace ts {
function isArrayLiteralExpression(node: Node): node is ArrayLiteralExpression;
function isObjectLiteralExpression(node: Node): node is ObjectLiteralExpression;
function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression;
function isPropertyAccessChain(node: Node): node is PropertyAccessChain;
function isElementAccessExpression(node: Node): node is ElementAccessExpression;
function isElementAccessChain(node: Node): node is ElementAccessChain;
function isCallExpression(node: Node): node is CallExpression;
function isCallChain(node: Node): node is CallChain;
function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain;
function isNewExpression(node: Node): node is NewExpression;
function isTaggedTemplateExpression(node: Node): node is TaggedTemplateExpression;
function isTypeAssertion(node: Node): node is TypeAssertion;
@@ -3943,10 +3965,16 @@ declare namespace ts {
function updateObjectLiteral(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]): ObjectLiteralExpression;
function createPropertyAccess(expression: Expression, name: string | Identifier): PropertyAccessExpression;
function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier): PropertyAccessExpression;
function createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier): PropertyAccessChain;
function updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier): PropertyAccessChain;
function createElementAccess(expression: Expression, index: number | Expression): ElementAccessExpression;
function updateElementAccess(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression;
function createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression): ElementAccessChain;
function updateElementAccessChain(node: ElementAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, argumentExpression: Expression): ElementAccessChain;
function createCall(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): CallExpression;
function updateCall(node: CallExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]): CallExpression;
function createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): CallChain;
function updateCallChain(node: CallChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]): CallChain;
function createNew(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): NewExpression;
function updateNew(node: NewExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): NewExpression;
/** @deprecated */ function createTaggedTemplate(tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
+365 -337
View File
@@ -104,332 +104,334 @@ declare namespace ts {
DotDotDotToken = 25,
SemicolonToken = 26,
CommaToken = 27,
LessThanToken = 28,
LessThanSlashToken = 29,
GreaterThanToken = 30,
LessThanEqualsToken = 31,
GreaterThanEqualsToken = 32,
EqualsEqualsToken = 33,
ExclamationEqualsToken = 34,
EqualsEqualsEqualsToken = 35,
ExclamationEqualsEqualsToken = 36,
EqualsGreaterThanToken = 37,
PlusToken = 38,
MinusToken = 39,
AsteriskToken = 40,
AsteriskAsteriskToken = 41,
SlashToken = 42,
PercentToken = 43,
PlusPlusToken = 44,
MinusMinusToken = 45,
LessThanLessThanToken = 46,
GreaterThanGreaterThanToken = 47,
GreaterThanGreaterThanGreaterThanToken = 48,
AmpersandToken = 49,
BarToken = 50,
CaretToken = 51,
ExclamationToken = 52,
TildeToken = 53,
AmpersandAmpersandToken = 54,
BarBarToken = 55,
QuestionToken = 56,
ColonToken = 57,
AtToken = 58,
QuestionDotToken = 28,
LessThanToken = 29,
LessThanSlashToken = 30,
GreaterThanToken = 31,
LessThanEqualsToken = 32,
GreaterThanEqualsToken = 33,
EqualsEqualsToken = 34,
ExclamationEqualsToken = 35,
EqualsEqualsEqualsToken = 36,
ExclamationEqualsEqualsToken = 37,
EqualsGreaterThanToken = 38,
PlusToken = 39,
MinusToken = 40,
AsteriskToken = 41,
AsteriskAsteriskToken = 42,
SlashToken = 43,
PercentToken = 44,
PlusPlusToken = 45,
MinusMinusToken = 46,
LessThanLessThanToken = 47,
GreaterThanGreaterThanToken = 48,
GreaterThanGreaterThanGreaterThanToken = 49,
AmpersandToken = 50,
BarToken = 51,
CaretToken = 52,
ExclamationToken = 53,
TildeToken = 54,
AmpersandAmpersandToken = 55,
BarBarToken = 56,
QuestionToken = 57,
ColonToken = 58,
AtToken = 59,
/** Only the JSDoc scanner produces BacktickToken. The normal scanner produces NoSubstitutionTemplateLiteral and related kinds. */
BacktickToken = 59,
EqualsToken = 60,
PlusEqualsToken = 61,
MinusEqualsToken = 62,
AsteriskEqualsToken = 63,
AsteriskAsteriskEqualsToken = 64,
SlashEqualsToken = 65,
PercentEqualsToken = 66,
LessThanLessThanEqualsToken = 67,
GreaterThanGreaterThanEqualsToken = 68,
GreaterThanGreaterThanGreaterThanEqualsToken = 69,
AmpersandEqualsToken = 70,
BarEqualsToken = 71,
CaretEqualsToken = 72,
Identifier = 73,
BreakKeyword = 74,
CaseKeyword = 75,
CatchKeyword = 76,
ClassKeyword = 77,
ConstKeyword = 78,
ContinueKeyword = 79,
DebuggerKeyword = 80,
DefaultKeyword = 81,
DeleteKeyword = 82,
DoKeyword = 83,
ElseKeyword = 84,
EnumKeyword = 85,
ExportKeyword = 86,
ExtendsKeyword = 87,
FalseKeyword = 88,
FinallyKeyword = 89,
ForKeyword = 90,
FunctionKeyword = 91,
IfKeyword = 92,
ImportKeyword = 93,
InKeyword = 94,
InstanceOfKeyword = 95,
NewKeyword = 96,
NullKeyword = 97,
ReturnKeyword = 98,
SuperKeyword = 99,
SwitchKeyword = 100,
ThisKeyword = 101,
ThrowKeyword = 102,
TrueKeyword = 103,
TryKeyword = 104,
TypeOfKeyword = 105,
VarKeyword = 106,
VoidKeyword = 107,
WhileKeyword = 108,
WithKeyword = 109,
ImplementsKeyword = 110,
InterfaceKeyword = 111,
LetKeyword = 112,
PackageKeyword = 113,
PrivateKeyword = 114,
ProtectedKeyword = 115,
PublicKeyword = 116,
StaticKeyword = 117,
YieldKeyword = 118,
AbstractKeyword = 119,
AsKeyword = 120,
AssertsKeyword = 121,
AnyKeyword = 122,
AsyncKeyword = 123,
AwaitKeyword = 124,
BooleanKeyword = 125,
ConstructorKeyword = 126,
DeclareKeyword = 127,
GetKeyword = 128,
InferKeyword = 129,
IsKeyword = 130,
KeyOfKeyword = 131,
ModuleKeyword = 132,
NamespaceKeyword = 133,
NeverKeyword = 134,
ReadonlyKeyword = 135,
RequireKeyword = 136,
NumberKeyword = 137,
ObjectKeyword = 138,
SetKeyword = 139,
StringKeyword = 140,
SymbolKeyword = 141,
TypeKeyword = 142,
UndefinedKeyword = 143,
UniqueKeyword = 144,
UnknownKeyword = 145,
FromKeyword = 146,
GlobalKeyword = 147,
BigIntKeyword = 148,
OfKeyword = 149,
QualifiedName = 150,
ComputedPropertyName = 151,
TypeParameter = 152,
Parameter = 153,
Decorator = 154,
PropertySignature = 155,
PropertyDeclaration = 156,
MethodSignature = 157,
MethodDeclaration = 158,
Constructor = 159,
GetAccessor = 160,
SetAccessor = 161,
CallSignature = 162,
ConstructSignature = 163,
IndexSignature = 164,
TypePredicate = 165,
TypeReference = 166,
FunctionType = 167,
ConstructorType = 168,
TypeQuery = 169,
TypeLiteral = 170,
ArrayType = 171,
TupleType = 172,
OptionalType = 173,
RestType = 174,
UnionType = 175,
IntersectionType = 176,
ConditionalType = 177,
InferType = 178,
ParenthesizedType = 179,
ThisType = 180,
TypeOperator = 181,
IndexedAccessType = 182,
MappedType = 183,
LiteralType = 184,
ImportType = 185,
ObjectBindingPattern = 186,
ArrayBindingPattern = 187,
BindingElement = 188,
ArrayLiteralExpression = 189,
ObjectLiteralExpression = 190,
PropertyAccessExpression = 191,
ElementAccessExpression = 192,
CallExpression = 193,
NewExpression = 194,
TaggedTemplateExpression = 195,
TypeAssertionExpression = 196,
ParenthesizedExpression = 197,
FunctionExpression = 198,
ArrowFunction = 199,
DeleteExpression = 200,
TypeOfExpression = 201,
VoidExpression = 202,
AwaitExpression = 203,
PrefixUnaryExpression = 204,
PostfixUnaryExpression = 205,
BinaryExpression = 206,
ConditionalExpression = 207,
TemplateExpression = 208,
YieldExpression = 209,
SpreadElement = 210,
ClassExpression = 211,
OmittedExpression = 212,
ExpressionWithTypeArguments = 213,
AsExpression = 214,
NonNullExpression = 215,
MetaProperty = 216,
SyntheticExpression = 217,
TemplateSpan = 218,
SemicolonClassElement = 219,
Block = 220,
EmptyStatement = 221,
VariableStatement = 222,
ExpressionStatement = 223,
IfStatement = 224,
DoStatement = 225,
WhileStatement = 226,
ForStatement = 227,
ForInStatement = 228,
ForOfStatement = 229,
ContinueStatement = 230,
BreakStatement = 231,
ReturnStatement = 232,
WithStatement = 233,
SwitchStatement = 234,
LabeledStatement = 235,
ThrowStatement = 236,
TryStatement = 237,
DebuggerStatement = 238,
VariableDeclaration = 239,
VariableDeclarationList = 240,
FunctionDeclaration = 241,
ClassDeclaration = 242,
InterfaceDeclaration = 243,
TypeAliasDeclaration = 244,
EnumDeclaration = 245,
ModuleDeclaration = 246,
ModuleBlock = 247,
CaseBlock = 248,
NamespaceExportDeclaration = 249,
ImportEqualsDeclaration = 250,
ImportDeclaration = 251,
ImportClause = 252,
NamespaceImport = 253,
NamedImports = 254,
ImportSpecifier = 255,
ExportAssignment = 256,
ExportDeclaration = 257,
NamedExports = 258,
ExportSpecifier = 259,
MissingDeclaration = 260,
ExternalModuleReference = 261,
JsxElement = 262,
JsxSelfClosingElement = 263,
JsxOpeningElement = 264,
JsxClosingElement = 265,
JsxFragment = 266,
JsxOpeningFragment = 267,
JsxClosingFragment = 268,
JsxAttribute = 269,
JsxAttributes = 270,
JsxSpreadAttribute = 271,
JsxExpression = 272,
CaseClause = 273,
DefaultClause = 274,
HeritageClause = 275,
CatchClause = 276,
PropertyAssignment = 277,
ShorthandPropertyAssignment = 278,
SpreadAssignment = 279,
EnumMember = 280,
UnparsedPrologue = 281,
UnparsedPrepend = 282,
UnparsedText = 283,
UnparsedInternalText = 284,
UnparsedSyntheticReference = 285,
SourceFile = 286,
Bundle = 287,
UnparsedSource = 288,
InputFiles = 289,
JSDocTypeExpression = 290,
JSDocAllType = 291,
JSDocUnknownType = 292,
JSDocNullableType = 293,
JSDocNonNullableType = 294,
JSDocOptionalType = 295,
JSDocFunctionType = 296,
JSDocVariadicType = 297,
JSDocNamepathType = 298,
JSDocComment = 299,
JSDocTypeLiteral = 300,
JSDocSignature = 301,
JSDocTag = 302,
JSDocAugmentsTag = 303,
JSDocAuthorTag = 304,
JSDocClassTag = 305,
JSDocCallbackTag = 306,
JSDocEnumTag = 307,
JSDocParameterTag = 308,
JSDocReturnTag = 309,
JSDocThisTag = 310,
JSDocTypeTag = 311,
JSDocTemplateTag = 312,
JSDocTypedefTag = 313,
JSDocPropertyTag = 314,
SyntaxList = 315,
NotEmittedStatement = 316,
PartiallyEmittedExpression = 317,
CommaListExpression = 318,
MergeDeclarationMarker = 319,
EndOfDeclarationMarker = 320,
Count = 321,
FirstAssignment = 60,
LastAssignment = 72,
FirstCompoundAssignment = 61,
LastCompoundAssignment = 72,
FirstReservedWord = 74,
LastReservedWord = 109,
FirstKeyword = 74,
LastKeyword = 149,
FirstFutureReservedWord = 110,
LastFutureReservedWord = 118,
FirstTypeNode = 165,
LastTypeNode = 185,
BacktickToken = 60,
EqualsToken = 61,
PlusEqualsToken = 62,
MinusEqualsToken = 63,
AsteriskEqualsToken = 64,
AsteriskAsteriskEqualsToken = 65,
SlashEqualsToken = 66,
PercentEqualsToken = 67,
LessThanLessThanEqualsToken = 68,
GreaterThanGreaterThanEqualsToken = 69,
GreaterThanGreaterThanGreaterThanEqualsToken = 70,
AmpersandEqualsToken = 71,
BarEqualsToken = 72,
CaretEqualsToken = 73,
Identifier = 74,
BreakKeyword = 75,
CaseKeyword = 76,
CatchKeyword = 77,
ClassKeyword = 78,
ConstKeyword = 79,
ContinueKeyword = 80,
DebuggerKeyword = 81,
DefaultKeyword = 82,
DeleteKeyword = 83,
DoKeyword = 84,
ElseKeyword = 85,
EnumKeyword = 86,
ExportKeyword = 87,
ExtendsKeyword = 88,
FalseKeyword = 89,
FinallyKeyword = 90,
ForKeyword = 91,
FunctionKeyword = 92,
IfKeyword = 93,
ImportKeyword = 94,
InKeyword = 95,
InstanceOfKeyword = 96,
NewKeyword = 97,
NullKeyword = 98,
ReturnKeyword = 99,
SuperKeyword = 100,
SwitchKeyword = 101,
ThisKeyword = 102,
ThrowKeyword = 103,
TrueKeyword = 104,
TryKeyword = 105,
TypeOfKeyword = 106,
VarKeyword = 107,
VoidKeyword = 108,
WhileKeyword = 109,
WithKeyword = 110,
ImplementsKeyword = 111,
InterfaceKeyword = 112,
LetKeyword = 113,
PackageKeyword = 114,
PrivateKeyword = 115,
ProtectedKeyword = 116,
PublicKeyword = 117,
StaticKeyword = 118,
YieldKeyword = 119,
AbstractKeyword = 120,
AsKeyword = 121,
AssertsKeyword = 122,
AnyKeyword = 123,
AsyncKeyword = 124,
AwaitKeyword = 125,
BooleanKeyword = 126,
ConstructorKeyword = 127,
DeclareKeyword = 128,
GetKeyword = 129,
InferKeyword = 130,
IsKeyword = 131,
KeyOfKeyword = 132,
ModuleKeyword = 133,
NamespaceKeyword = 134,
NeverKeyword = 135,
ReadonlyKeyword = 136,
RequireKeyword = 137,
NumberKeyword = 138,
ObjectKeyword = 139,
SetKeyword = 140,
StringKeyword = 141,
SymbolKeyword = 142,
TypeKeyword = 143,
UndefinedKeyword = 144,
UniqueKeyword = 145,
UnknownKeyword = 146,
FromKeyword = 147,
GlobalKeyword = 148,
BigIntKeyword = 149,
OfKeyword = 150,
QualifiedName = 151,
ComputedPropertyName = 152,
TypeParameter = 153,
Parameter = 154,
Decorator = 155,
PropertySignature = 156,
PropertyDeclaration = 157,
MethodSignature = 158,
MethodDeclaration = 159,
Constructor = 160,
GetAccessor = 161,
SetAccessor = 162,
CallSignature = 163,
ConstructSignature = 164,
IndexSignature = 165,
TypePredicate = 166,
TypeReference = 167,
FunctionType = 168,
ConstructorType = 169,
TypeQuery = 170,
TypeLiteral = 171,
ArrayType = 172,
TupleType = 173,
OptionalType = 174,
RestType = 175,
UnionType = 176,
IntersectionType = 177,
ConditionalType = 178,
InferType = 179,
ParenthesizedType = 180,
ThisType = 181,
TypeOperator = 182,
IndexedAccessType = 183,
MappedType = 184,
LiteralType = 185,
ImportType = 186,
ObjectBindingPattern = 187,
ArrayBindingPattern = 188,
BindingElement = 189,
ArrayLiteralExpression = 190,
ObjectLiteralExpression = 191,
PropertyAccessExpression = 192,
ElementAccessExpression = 193,
CallExpression = 194,
NewExpression = 195,
TaggedTemplateExpression = 196,
TypeAssertionExpression = 197,
ParenthesizedExpression = 198,
FunctionExpression = 199,
ArrowFunction = 200,
DeleteExpression = 201,
TypeOfExpression = 202,
VoidExpression = 203,
AwaitExpression = 204,
PrefixUnaryExpression = 205,
PostfixUnaryExpression = 206,
BinaryExpression = 207,
ConditionalExpression = 208,
TemplateExpression = 209,
YieldExpression = 210,
SpreadElement = 211,
ClassExpression = 212,
OmittedExpression = 213,
ExpressionWithTypeArguments = 214,
AsExpression = 215,
NonNullExpression = 216,
MetaProperty = 217,
SyntheticExpression = 218,
TemplateSpan = 219,
SemicolonClassElement = 220,
Block = 221,
EmptyStatement = 222,
VariableStatement = 223,
ExpressionStatement = 224,
IfStatement = 225,
DoStatement = 226,
WhileStatement = 227,
ForStatement = 228,
ForInStatement = 229,
ForOfStatement = 230,
ContinueStatement = 231,
BreakStatement = 232,
ReturnStatement = 233,
WithStatement = 234,
SwitchStatement = 235,
LabeledStatement = 236,
ThrowStatement = 237,
TryStatement = 238,
DebuggerStatement = 239,
VariableDeclaration = 240,
VariableDeclarationList = 241,
FunctionDeclaration = 242,
ClassDeclaration = 243,
InterfaceDeclaration = 244,
TypeAliasDeclaration = 245,
EnumDeclaration = 246,
ModuleDeclaration = 247,
ModuleBlock = 248,
CaseBlock = 249,
NamespaceExportDeclaration = 250,
ImportEqualsDeclaration = 251,
ImportDeclaration = 252,
ImportClause = 253,
NamespaceImport = 254,
NamedImports = 255,
ImportSpecifier = 256,
ExportAssignment = 257,
ExportDeclaration = 258,
NamedExports = 259,
ExportSpecifier = 260,
MissingDeclaration = 261,
ExternalModuleReference = 262,
JsxElement = 263,
JsxSelfClosingElement = 264,
JsxOpeningElement = 265,
JsxClosingElement = 266,
JsxFragment = 267,
JsxOpeningFragment = 268,
JsxClosingFragment = 269,
JsxAttribute = 270,
JsxAttributes = 271,
JsxSpreadAttribute = 272,
JsxExpression = 273,
CaseClause = 274,
DefaultClause = 275,
HeritageClause = 276,
CatchClause = 277,
PropertyAssignment = 278,
ShorthandPropertyAssignment = 279,
SpreadAssignment = 280,
EnumMember = 281,
UnparsedPrologue = 282,
UnparsedPrepend = 283,
UnparsedText = 284,
UnparsedInternalText = 285,
UnparsedSyntheticReference = 286,
SourceFile = 287,
Bundle = 288,
UnparsedSource = 289,
InputFiles = 290,
JSDocTypeExpression = 291,
JSDocAllType = 292,
JSDocUnknownType = 293,
JSDocNullableType = 294,
JSDocNonNullableType = 295,
JSDocOptionalType = 296,
JSDocFunctionType = 297,
JSDocVariadicType = 298,
JSDocNamepathType = 299,
JSDocComment = 300,
JSDocTypeLiteral = 301,
JSDocSignature = 302,
JSDocTag = 303,
JSDocAugmentsTag = 304,
JSDocAuthorTag = 305,
JSDocClassTag = 306,
JSDocCallbackTag = 307,
JSDocEnumTag = 308,
JSDocParameterTag = 309,
JSDocReturnTag = 310,
JSDocThisTag = 311,
JSDocTypeTag = 312,
JSDocTemplateTag = 313,
JSDocTypedefTag = 314,
JSDocPropertyTag = 315,
SyntaxList = 316,
NotEmittedStatement = 317,
PartiallyEmittedExpression = 318,
CommaListExpression = 319,
MergeDeclarationMarker = 320,
EndOfDeclarationMarker = 321,
SyntheticReferenceExpression = 322,
Count = 323,
FirstAssignment = 61,
LastAssignment = 73,
FirstCompoundAssignment = 62,
LastCompoundAssignment = 73,
FirstReservedWord = 75,
LastReservedWord = 110,
FirstKeyword = 75,
LastKeyword = 150,
FirstFutureReservedWord = 111,
LastFutureReservedWord = 119,
FirstTypeNode = 166,
LastTypeNode = 186,
FirstPunctuation = 18,
LastPunctuation = 72,
LastPunctuation = 73,
FirstToken = 0,
LastToken = 149,
LastToken = 150,
FirstTriviaToken = 2,
LastTriviaToken = 7,
FirstLiteralToken = 8,
LastLiteralToken = 14,
FirstTemplateToken = 14,
LastTemplateToken = 17,
FirstBinaryOperator = 28,
LastBinaryOperator = 72,
FirstStatement = 222,
LastStatement = 238,
FirstNode = 150,
FirstJSDocNode = 290,
LastJSDocNode = 314,
FirstJSDocTagNode = 302,
LastJSDocTagNode = 314,
FirstBinaryOperator = 29,
LastBinaryOperator = 73,
FirstStatement = 223,
LastStatement = 239,
FirstNode = 151,
FirstJSDocNode = 291,
LastJSDocNode = 315,
FirstJSDocTagNode = 303,
LastJSDocTagNode = 315,
}
export enum NodeFlags {
None = 0,
@@ -438,27 +440,28 @@ declare namespace ts {
NestedNamespace = 4,
Synthesized = 8,
Namespace = 16,
ExportContext = 32,
ContainsThis = 64,
HasImplicitReturn = 128,
HasExplicitReturn = 256,
GlobalAugmentation = 512,
HasAsyncFunctions = 1024,
DisallowInContext = 2048,
YieldContext = 4096,
DecoratorContext = 8192,
AwaitContext = 16384,
ThisNodeHasError = 32768,
JavaScriptFile = 65536,
ThisNodeOrAnySubNodesHasError = 131072,
HasAggregatedChildData = 262144,
JSDoc = 2097152,
JsonFile = 16777216,
OptionalChain = 32,
ExportContext = 64,
ContainsThis = 128,
HasImplicitReturn = 256,
HasExplicitReturn = 512,
GlobalAugmentation = 1024,
HasAsyncFunctions = 2048,
DisallowInContext = 4096,
YieldContext = 8192,
DecoratorContext = 16384,
AwaitContext = 32768,
ThisNodeHasError = 65536,
JavaScriptFile = 131072,
ThisNodeOrAnySubNodesHasError = 262144,
HasAggregatedChildData = 524288,
JSDoc = 4194304,
JsonFile = 33554432,
BlockScoped = 3,
ReachabilityCheckFlags = 384,
ReachabilityAndEmitFlags = 1408,
ContextFlags = 12679168,
TypeExcludesFlags = 20480,
ReachabilityCheckFlags = 768,
ReachabilityAndEmitFlags = 2816,
ContextFlags = 25358336,
TypeExcludesFlags = 40960,
}
export enum ModifierFlags {
None = 0,
@@ -508,8 +511,10 @@ declare namespace ts {
export interface Token<TKind extends SyntaxKind> extends Node {
kind: TKind;
}
export type DotToken = Token<SyntaxKind.DotToken>;
export type DotDotDotToken = Token<SyntaxKind.DotDotDotToken>;
export type QuestionToken = Token<SyntaxKind.QuestionToken>;
export type QuestionDotToken = Token<SyntaxKind.QuestionDotToken>;
export type ExclamationToken = Token<SyntaxKind.ExclamationToken>;
export type ColonToken = Token<SyntaxKind.ColonToken>;
export type EqualsToken = Token<SyntaxKind.EqualsToken>;
@@ -1082,8 +1087,12 @@ declare namespace ts {
export interface PropertyAccessExpression extends MemberExpression, NamedDeclaration {
kind: SyntaxKind.PropertyAccessExpression;
expression: LeftHandSideExpression;
questionDotToken?: QuestionDotToken;
name: Identifier;
}
export interface PropertyAccessChain extends PropertyAccessExpression {
_optionalChainBrand: any;
}
export interface SuperPropertyAccessExpression extends PropertyAccessExpression {
expression: SuperExpression;
}
@@ -1095,8 +1104,12 @@ declare namespace ts {
export interface ElementAccessExpression extends MemberExpression {
kind: SyntaxKind.ElementAccessExpression;
expression: LeftHandSideExpression;
questionDotToken?: QuestionDotToken;
argumentExpression: Expression;
}
export interface ElementAccessChain extends ElementAccessExpression {
_optionalChainBrand: any;
}
export interface SuperElementAccessExpression extends ElementAccessExpression {
expression: SuperExpression;
}
@@ -1104,9 +1117,14 @@ declare namespace ts {
export interface CallExpression extends LeftHandSideExpression, Declaration {
kind: SyntaxKind.CallExpression;
expression: LeftHandSideExpression;
questionDotToken?: QuestionDotToken;
typeArguments?: NodeArray<TypeNode>;
arguments: NodeArray<Expression>;
}
export interface CallChain extends CallExpression {
_optionalChainBrand: any;
}
export type OptionalChain = PropertyAccessChain | ElementAccessChain | CallChain;
export interface SuperCall extends CallExpression {
expression: SuperExpression;
}
@@ -3496,8 +3514,12 @@ declare namespace ts {
function isArrayLiteralExpression(node: Node): node is ArrayLiteralExpression;
function isObjectLiteralExpression(node: Node): node is ObjectLiteralExpression;
function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression;
function isPropertyAccessChain(node: Node): node is PropertyAccessChain;
function isElementAccessExpression(node: Node): node is ElementAccessExpression;
function isElementAccessChain(node: Node): node is ElementAccessChain;
function isCallExpression(node: Node): node is CallExpression;
function isCallChain(node: Node): node is CallChain;
function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain;
function isNewExpression(node: Node): node is NewExpression;
function isTaggedTemplateExpression(node: Node): node is TaggedTemplateExpression;
function isTypeAssertion(node: Node): node is TypeAssertion;
@@ -3943,10 +3965,16 @@ declare namespace ts {
function updateObjectLiteral(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]): ObjectLiteralExpression;
function createPropertyAccess(expression: Expression, name: string | Identifier): PropertyAccessExpression;
function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier): PropertyAccessExpression;
function createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier): PropertyAccessChain;
function updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier): PropertyAccessChain;
function createElementAccess(expression: Expression, index: number | Expression): ElementAccessExpression;
function updateElementAccess(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression;
function createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression): ElementAccessChain;
function updateElementAccessChain(node: ElementAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, argumentExpression: Expression): ElementAccessChain;
function createCall(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): CallExpression;
function updateCall(node: CallExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]): CallExpression;
function createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): CallChain;
function updateCallChain(node: CallChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]): CallChain;
function createNew(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): NewExpression;
function updateNew(node: NewExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): NewExpression;
/** @deprecated */ function createTaggedTemplate(tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
+16
View File
@@ -0,0 +1,16 @@
//// [callChain.2.ts]
declare const o1: undefined | (() => number);
o1?.();
declare const o2: undefined | { b: () => number };
o2?.b();
declare const o3: { b: (() => { c: string }) | undefined };
o3.b?.().c;
//// [callChain.2.js]
var _a, _b, _c, _d;
(_a = o1) === null || _a === void 0 ? void 0 : _a();
(_b = o2) === null || _b === void 0 ? void 0 : _b.b();
(_d = (_c = o3).b) === null || _d === void 0 ? void 0 : _d.call(_c).c;
@@ -0,0 +1,28 @@
=== tests/cases/conformance/expressions/optionalChaining/callChain/callChain.2.ts ===
declare const o1: undefined | (() => number);
>o1 : Symbol(o1, Decl(callChain.2.ts, 0, 13))
o1?.();
>o1 : Symbol(o1, Decl(callChain.2.ts, 0, 13))
declare const o2: undefined | { b: () => number };
>o2 : Symbol(o2, Decl(callChain.2.ts, 3, 13))
>b : Symbol(b, Decl(callChain.2.ts, 3, 31))
o2?.b();
>o2?.b : Symbol(b, Decl(callChain.2.ts, 3, 31))
>o2 : Symbol(o2, Decl(callChain.2.ts, 3, 13))
>b : Symbol(b, Decl(callChain.2.ts, 3, 31))
declare const o3: { b: (() => { c: string }) | undefined };
>o3 : Symbol(o3, Decl(callChain.2.ts, 6, 13))
>b : Symbol(b, Decl(callChain.2.ts, 6, 19))
>c : Symbol(c, Decl(callChain.2.ts, 6, 31))
o3.b?.().c;
>o3.b?.().c : Symbol(c, Decl(callChain.2.ts, 6, 31))
>o3.b : Symbol(b, Decl(callChain.2.ts, 6, 19))
>o3 : Symbol(o3, Decl(callChain.2.ts, 6, 13))
>b : Symbol(b, Decl(callChain.2.ts, 6, 19))
>c : Symbol(c, Decl(callChain.2.ts, 6, 31))
@@ -0,0 +1,31 @@
=== tests/cases/conformance/expressions/optionalChaining/callChain/callChain.2.ts ===
declare const o1: undefined | (() => number);
>o1 : () => number
o1?.();
>o1?.() : number
>o1 : () => number
declare const o2: undefined | { b: () => number };
>o2 : { b: () => number; }
>b : () => number
o2?.b();
>o2?.b() : number
>o2?.b : () => number
>o2 : { b: () => number; }
>b : () => number
declare const o3: { b: (() => { c: string }) | undefined };
>o3 : { b: () => { c: string; }; }
>b : () => { c: string; }
>c : string
o3.b?.().c;
>o3.b?.().c : string
>o3.b?.() : { c: string; }
>o3.b : () => { c: string; }
>o3 : { b: () => { c: string; }; }
>b : () => { c: string; }
>c : string
@@ -0,0 +1,23 @@
tests/cases/conformance/expressions/optionalChaining/callChain/callChain.3.ts(3,7): error TS2322: Type 'number | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.
tests/cases/conformance/expressions/optionalChaining/callChain/callChain.3.ts(4,7): error TS2322: Type 'number | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.
==== tests/cases/conformance/expressions/optionalChaining/callChain/callChain.3.ts (2 errors) ====
declare function absorb<T>(): T;
declare const a: { m?<T>(obj: {x: T}): T } | undefined;
const n1: number = a?.m?.({x: 12 }); // should be an error (`undefined` is not assignable to `number`)
~~
!!! error TS2322: Type 'number | undefined' is not assignable to type 'number'.
!!! error TS2322: Type 'undefined' is not assignable to type 'number'.
const n2: number = a?.m?.({x: absorb()}); // likewise
~~
!!! error TS2322: Type 'number | undefined' is not assignable to type 'number'.
!!! error TS2322: Type 'undefined' is not assignable to type 'number'.
const n3: number | undefined = a?.m?.({x: 12}); // should be ok
const n4: number | undefined = a?.m?.({x: absorb()}); // likewise
// Also a test showing `!` vs `?` for good measure
let t1 = a?.m?.({x: 12});
t1 = a!.m!({x: 12});
+22
View File
@@ -0,0 +1,22 @@
//// [callChain.3.ts]
declare function absorb<T>(): T;
declare const a: { m?<T>(obj: {x: T}): T } | undefined;
const n1: number = a?.m?.({x: 12 }); // should be an error (`undefined` is not assignable to `number`)
const n2: number = a?.m?.({x: absorb()}); // likewise
const n3: number | undefined = a?.m?.({x: 12}); // should be ok
const n4: number | undefined = a?.m?.({x: absorb()}); // likewise
// Also a test showing `!` vs `?` for good measure
let t1 = a?.m?.({x: 12});
t1 = a!.m!({x: 12});
//// [callChain.3.js]
"use strict";
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
var n1 = (_c = (_a = a) === null || _a === void 0 ? void 0 : (_b = _a).m) === null || _c === void 0 ? void 0 : _c.call(_b, { x: 12 }); // should be an error (`undefined` is not assignable to `number`)
var n2 = (_f = (_d = a) === null || _d === void 0 ? void 0 : (_e = _d).m) === null || _f === void 0 ? void 0 : _f.call(_e, { x: absorb() }); // likewise
var n3 = (_j = (_g = a) === null || _g === void 0 ? void 0 : (_h = _g).m) === null || _j === void 0 ? void 0 : _j.call(_h, { x: 12 }); // should be ok
var n4 = (_m = (_k = a) === null || _k === void 0 ? void 0 : (_l = _k).m) === null || _m === void 0 ? void 0 : _m.call(_l, { x: absorb() }); // likewise
// Also a test showing `!` vs `?` for good measure
var t1 = (_q = (_o = a) === null || _o === void 0 ? void 0 : (_p = _o).m) === null || _q === void 0 ? void 0 : _q.call(_p, { x: 12 });
t1 = a.m({ x: 12 });
@@ -0,0 +1,60 @@
=== tests/cases/conformance/expressions/optionalChaining/callChain/callChain.3.ts ===
declare function absorb<T>(): T;
>absorb : Symbol(absorb, Decl(callChain.3.ts, 0, 0))
>T : Symbol(T, Decl(callChain.3.ts, 0, 24))
>T : Symbol(T, Decl(callChain.3.ts, 0, 24))
declare const a: { m?<T>(obj: {x: T}): T } | undefined;
>a : Symbol(a, Decl(callChain.3.ts, 1, 13))
>m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>T : Symbol(T, Decl(callChain.3.ts, 1, 22))
>obj : Symbol(obj, Decl(callChain.3.ts, 1, 25))
>x : Symbol(x, Decl(callChain.3.ts, 1, 31))
>T : Symbol(T, Decl(callChain.3.ts, 1, 22))
>T : Symbol(T, Decl(callChain.3.ts, 1, 22))
const n1: number = a?.m?.({x: 12 }); // should be an error (`undefined` is not assignable to `number`)
>n1 : Symbol(n1, Decl(callChain.3.ts, 2, 5))
>a?.m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>a : Symbol(a, Decl(callChain.3.ts, 1, 13))
>m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>x : Symbol(x, Decl(callChain.3.ts, 2, 27))
const n2: number = a?.m?.({x: absorb()}); // likewise
>n2 : Symbol(n2, Decl(callChain.3.ts, 3, 5))
>a?.m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>a : Symbol(a, Decl(callChain.3.ts, 1, 13))
>m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>x : Symbol(x, Decl(callChain.3.ts, 3, 27))
>absorb : Symbol(absorb, Decl(callChain.3.ts, 0, 0))
const n3: number | undefined = a?.m?.({x: 12}); // should be ok
>n3 : Symbol(n3, Decl(callChain.3.ts, 4, 5))
>a?.m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>a : Symbol(a, Decl(callChain.3.ts, 1, 13))
>m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>x : Symbol(x, Decl(callChain.3.ts, 4, 39))
const n4: number | undefined = a?.m?.({x: absorb()}); // likewise
>n4 : Symbol(n4, Decl(callChain.3.ts, 5, 5))
>a?.m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>a : Symbol(a, Decl(callChain.3.ts, 1, 13))
>m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>x : Symbol(x, Decl(callChain.3.ts, 5, 39))
>absorb : Symbol(absorb, Decl(callChain.3.ts, 0, 0))
// Also a test showing `!` vs `?` for good measure
let t1 = a?.m?.({x: 12});
>t1 : Symbol(t1, Decl(callChain.3.ts, 8, 3))
>a?.m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>a : Symbol(a, Decl(callChain.3.ts, 1, 13))
>m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>x : Symbol(x, Decl(callChain.3.ts, 8, 17))
t1 = a!.m!({x: 12});
>t1 : Symbol(t1, Decl(callChain.3.ts, 8, 3))
>a!.m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>a : Symbol(a, Decl(callChain.3.ts, 1, 13))
>m : Symbol(m, Decl(callChain.3.ts, 1, 18))
>x : Symbol(x, Decl(callChain.3.ts, 9, 12))
@@ -0,0 +1,76 @@
=== tests/cases/conformance/expressions/optionalChaining/callChain/callChain.3.ts ===
declare function absorb<T>(): T;
>absorb : <T>() => T
declare const a: { m?<T>(obj: {x: T}): T } | undefined;
>a : { m?<T>(obj: { x: T; }): T; } | undefined
>m : (<T>(obj: { x: T; }) => T) | undefined
>obj : { x: T; }
>x : T
const n1: number = a?.m?.({x: 12 }); // should be an error (`undefined` is not assignable to `number`)
>n1 : number
>a?.m?.({x: 12 }) : number | undefined
>a?.m : (<T>(obj: { x: T; }) => T) | undefined
>a : { m?<T>(obj: { x: T; }): T; } | undefined
>m : (<T>(obj: { x: T; }) => T) | undefined
>{x: 12 } : { x: number; }
>x : number
>12 : 12
const n2: number = a?.m?.({x: absorb()}); // likewise
>n2 : number
>a?.m?.({x: absorb()}) : number | undefined
>a?.m : (<T>(obj: { x: T; }) => T) | undefined
>a : { m?<T>(obj: { x: T; }): T; } | undefined
>m : (<T>(obj: { x: T; }) => T) | undefined
>{x: absorb()} : { x: number; }
>x : number
>absorb() : number
>absorb : <T>() => T
const n3: number | undefined = a?.m?.({x: 12}); // should be ok
>n3 : number | undefined
>a?.m?.({x: 12}) : number | undefined
>a?.m : (<T>(obj: { x: T; }) => T) | undefined
>a : { m?<T>(obj: { x: T; }): T; } | undefined
>m : (<T>(obj: { x: T; }) => T) | undefined
>{x: 12} : { x: number; }
>x : number
>12 : 12
const n4: number | undefined = a?.m?.({x: absorb()}); // likewise
>n4 : number | undefined
>a?.m?.({x: absorb()}) : number | undefined
>a?.m : (<T>(obj: { x: T; }) => T) | undefined
>a : { m?<T>(obj: { x: T; }): T; } | undefined
>m : (<T>(obj: { x: T; }) => T) | undefined
>{x: absorb()} : { x: number | undefined; }
>x : number | undefined
>absorb() : number | undefined
>absorb : <T>() => T
// Also a test showing `!` vs `?` for good measure
let t1 = a?.m?.({x: 12});
>t1 : number | undefined
>a?.m?.({x: 12}) : number | undefined
>a?.m : (<T>(obj: { x: T; }) => T) | undefined
>a : { m?<T>(obj: { x: T; }): T; } | undefined
>m : (<T>(obj: { x: T; }) => T) | undefined
>{x: 12} : { x: number; }
>x : number
>12 : 12
t1 = a!.m!({x: 12});
>t1 = a!.m!({x: 12}) : number
>t1 : number | undefined
>a!.m!({x: 12}) : number
>a!.m! : <T>(obj: { x: T; }) => T
>a!.m : (<T>(obj: { x: T; }) => T) | undefined
>a! : { m?<T>(obj: { x: T; }): T; }
>a : { m?<T>(obj: { x: T; }): T; } | undefined
>m : (<T>(obj: { x: T; }) => T) | undefined
>{x: 12} : { x: number; }
>x : number
>12 : 12
+70
View File
@@ -0,0 +1,70 @@
//// [callChain.ts]
declare const o1: undefined | ((...args: any[]) => number);
o1?.();
o1?.(1);
o1?.(...[1, 2]);
o1?.(1, ...[2, 3], 4);
declare const o2: undefined | { b: (...args: any[]) => number };
o2?.b();
o2?.b(1);
o2?.b(...[1, 2]);
o2?.b(1, ...[2, 3], 4);
o2?.["b"]();
o2?.["b"](1);
o2?.["b"](...[1, 2]);
o2?.["b"](1, ...[2, 3], 4);
declare const o3: { b: ((...args: any[]) => { c: string }) | undefined };
o3.b?.().c;
o3.b?.(1).c;
o3.b?.(...[1, 2]).c;
o3.b?.(1, ...[2, 3], 4).c;
o3.b?.()["c"];
o3.b?.(1)["c"];
o3.b?.(...[1, 2])["c"];
o3.b?.(1, ...[2, 3], 4)["c"];
o3["b"]?.().c;
o3["b"]?.(1).c;
o3["b"]?.(...[1, 2]).c;
o3["b"]?.(1, ...[2, 3], 4).c;
declare const o4: undefined | (<T>(f: (a: T) => T) => T);
declare function incr(x: number): number;
const v: number | undefined = o4?.(incr);
//// [callChain.js]
"use strict";
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12;
(_a = o1) === null || _a === void 0 ? void 0 : _a();
(_b = o1) === null || _b === void 0 ? void 0 : _b(1);
(_c = o1) === null || _c === void 0 ? void 0 : _c.apply(void 0, [1, 2]);
(_d = o1) === null || _d === void 0 ? void 0 : _d.apply(void 0, __spreadArrays([1], [2, 3], [4]));
(_e = o2) === null || _e === void 0 ? void 0 : _e.b();
(_f = o2) === null || _f === void 0 ? void 0 : _f.b(1);
(_g = o2) === null || _g === void 0 ? void 0 : _g.b.apply(_g, [1, 2]);
(_h = o2) === null || _h === void 0 ? void 0 : _h.b.apply(_h, __spreadArrays([1], [2, 3], [4]));
(_j = o2) === null || _j === void 0 ? void 0 : _j["b"]();
(_k = o2) === null || _k === void 0 ? void 0 : _k["b"](1);
(_l = o2) === null || _l === void 0 ? void 0 : _l["b"].apply(_l, [1, 2]);
(_m = o2) === null || _m === void 0 ? void 0 : _m["b"].apply(_m, __spreadArrays([1], [2, 3], [4]));
(_p = (_o = o3).b) === null || _p === void 0 ? void 0 : _p.call(_o).c;
(_r = (_q = o3).b) === null || _r === void 0 ? void 0 : _r.call(_q, 1).c;
(_t = (_s = o3).b) === null || _t === void 0 ? void 0 : _t.call.apply(_t, __spreadArrays([_s], [1, 2])).c;
(_v = (_u = o3).b) === null || _v === void 0 ? void 0 : _v.call.apply(_v, __spreadArrays([_u, 1], [2, 3], [4])).c;
(_x = (_w = o3).b) === null || _x === void 0 ? void 0 : _x.call(_w)["c"];
(_z = (_y = o3).b) === null || _z === void 0 ? void 0 : _z.call(_y, 1)["c"];
(_1 = (_0 = o3).b) === null || _1 === void 0 ? void 0 : _1.call.apply(_1, __spreadArrays([_0], [1, 2]))["c"];
(_3 = (_2 = o3).b) === null || _3 === void 0 ? void 0 : _3.call.apply(_3, __spreadArrays([_2, 1], [2, 3], [4]))["c"];
(_5 = (_4 = o3)["b"]) === null || _5 === void 0 ? void 0 : _5.call(_4).c;
(_7 = (_6 = o3)["b"]) === null || _7 === void 0 ? void 0 : _7.call(_6, 1).c;
(_9 = (_8 = o3)["b"]) === null || _9 === void 0 ? void 0 : _9.call.apply(_9, __spreadArrays([_8], [1, 2])).c;
(_11 = (_10 = o3)["b"]) === null || _11 === void 0 ? void 0 : _11.call.apply(_11, __spreadArrays([_10, 1], [2, 3], [4])).c;
var v = (_12 = o4) === null || _12 === void 0 ? void 0 : _12(incr);
+150
View File
@@ -0,0 +1,150 @@
=== tests/cases/conformance/expressions/optionalChaining/callChain/callChain.ts ===
declare const o1: undefined | ((...args: any[]) => number);
>o1 : Symbol(o1, Decl(callChain.ts, 0, 13))
>args : Symbol(args, Decl(callChain.ts, 0, 32))
o1?.();
>o1 : Symbol(o1, Decl(callChain.ts, 0, 13))
o1?.(1);
>o1 : Symbol(o1, Decl(callChain.ts, 0, 13))
o1?.(...[1, 2]);
>o1 : Symbol(o1, Decl(callChain.ts, 0, 13))
o1?.(1, ...[2, 3], 4);
>o1 : Symbol(o1, Decl(callChain.ts, 0, 13))
declare const o2: undefined | { b: (...args: any[]) => number };
>o2 : Symbol(o2, Decl(callChain.ts, 6, 13))
>b : Symbol(b, Decl(callChain.ts, 6, 31))
>args : Symbol(args, Decl(callChain.ts, 6, 36))
o2?.b();
>o2?.b : Symbol(b, Decl(callChain.ts, 6, 31))
>o2 : Symbol(o2, Decl(callChain.ts, 6, 13))
>b : Symbol(b, Decl(callChain.ts, 6, 31))
o2?.b(1);
>o2?.b : Symbol(b, Decl(callChain.ts, 6, 31))
>o2 : Symbol(o2, Decl(callChain.ts, 6, 13))
>b : Symbol(b, Decl(callChain.ts, 6, 31))
o2?.b(...[1, 2]);
>o2?.b : Symbol(b, Decl(callChain.ts, 6, 31))
>o2 : Symbol(o2, Decl(callChain.ts, 6, 13))
>b : Symbol(b, Decl(callChain.ts, 6, 31))
o2?.b(1, ...[2, 3], 4);
>o2?.b : Symbol(b, Decl(callChain.ts, 6, 31))
>o2 : Symbol(o2, Decl(callChain.ts, 6, 13))
>b : Symbol(b, Decl(callChain.ts, 6, 31))
o2?.["b"]();
>o2 : Symbol(o2, Decl(callChain.ts, 6, 13))
o2?.["b"](1);
>o2 : Symbol(o2, Decl(callChain.ts, 6, 13))
o2?.["b"](...[1, 2]);
>o2 : Symbol(o2, Decl(callChain.ts, 6, 13))
o2?.["b"](1, ...[2, 3], 4);
>o2 : Symbol(o2, Decl(callChain.ts, 6, 13))
declare const o3: { b: ((...args: any[]) => { c: string }) | undefined };
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>b : Symbol(b, Decl(callChain.ts, 16, 19))
>args : Symbol(args, Decl(callChain.ts, 16, 25))
>c : Symbol(c, Decl(callChain.ts, 16, 45))
o3.b?.().c;
>o3.b?.().c : Symbol(c, Decl(callChain.ts, 16, 45))
>o3.b : Symbol(b, Decl(callChain.ts, 16, 19))
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>b : Symbol(b, Decl(callChain.ts, 16, 19))
>c : Symbol(c, Decl(callChain.ts, 16, 45))
o3.b?.(1).c;
>o3.b?.(1).c : Symbol(c, Decl(callChain.ts, 16, 45))
>o3.b : Symbol(b, Decl(callChain.ts, 16, 19))
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>b : Symbol(b, Decl(callChain.ts, 16, 19))
>c : Symbol(c, Decl(callChain.ts, 16, 45))
o3.b?.(...[1, 2]).c;
>o3.b?.(...[1, 2]).c : Symbol(c, Decl(callChain.ts, 16, 45))
>o3.b : Symbol(b, Decl(callChain.ts, 16, 19))
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>b : Symbol(b, Decl(callChain.ts, 16, 19))
>c : Symbol(c, Decl(callChain.ts, 16, 45))
o3.b?.(1, ...[2, 3], 4).c;
>o3.b?.(1, ...[2, 3], 4).c : Symbol(c, Decl(callChain.ts, 16, 45))
>o3.b : Symbol(b, Decl(callChain.ts, 16, 19))
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>b : Symbol(b, Decl(callChain.ts, 16, 19))
>c : Symbol(c, Decl(callChain.ts, 16, 45))
o3.b?.()["c"];
>o3.b : Symbol(b, Decl(callChain.ts, 16, 19))
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>b : Symbol(b, Decl(callChain.ts, 16, 19))
o3.b?.(1)["c"];
>o3.b : Symbol(b, Decl(callChain.ts, 16, 19))
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>b : Symbol(b, Decl(callChain.ts, 16, 19))
o3.b?.(...[1, 2])["c"];
>o3.b : Symbol(b, Decl(callChain.ts, 16, 19))
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>b : Symbol(b, Decl(callChain.ts, 16, 19))
o3.b?.(1, ...[2, 3], 4)["c"];
>o3.b : Symbol(b, Decl(callChain.ts, 16, 19))
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>b : Symbol(b, Decl(callChain.ts, 16, 19))
o3["b"]?.().c;
>o3["b"]?.().c : Symbol(c, Decl(callChain.ts, 16, 45))
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>"b" : Symbol(b, Decl(callChain.ts, 16, 19))
>c : Symbol(c, Decl(callChain.ts, 16, 45))
o3["b"]?.(1).c;
>o3["b"]?.(1).c : Symbol(c, Decl(callChain.ts, 16, 45))
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>"b" : Symbol(b, Decl(callChain.ts, 16, 19))
>c : Symbol(c, Decl(callChain.ts, 16, 45))
o3["b"]?.(...[1, 2]).c;
>o3["b"]?.(...[1, 2]).c : Symbol(c, Decl(callChain.ts, 16, 45))
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>"b" : Symbol(b, Decl(callChain.ts, 16, 19))
>c : Symbol(c, Decl(callChain.ts, 16, 45))
o3["b"]?.(1, ...[2, 3], 4).c;
>o3["b"]?.(1, ...[2, 3], 4).c : Symbol(c, Decl(callChain.ts, 16, 45))
>o3 : Symbol(o3, Decl(callChain.ts, 16, 13))
>"b" : Symbol(b, Decl(callChain.ts, 16, 19))
>c : Symbol(c, Decl(callChain.ts, 16, 45))
declare const o4: undefined | (<T>(f: (a: T) => T) => T);
>o4 : Symbol(o4, Decl(callChain.ts, 30, 13))
>T : Symbol(T, Decl(callChain.ts, 30, 32))
>f : Symbol(f, Decl(callChain.ts, 30, 35))
>a : Symbol(a, Decl(callChain.ts, 30, 39))
>T : Symbol(T, Decl(callChain.ts, 30, 32))
>T : Symbol(T, Decl(callChain.ts, 30, 32))
>T : Symbol(T, Decl(callChain.ts, 30, 32))
declare function incr(x: number): number;
>incr : Symbol(incr, Decl(callChain.ts, 30, 57))
>x : Symbol(x, Decl(callChain.ts, 31, 22))
const v: number | undefined = o4?.(incr);
>v : Symbol(v, Decl(callChain.ts, 32, 5))
>o4 : Symbol(o4, Decl(callChain.ts, 30, 13))
>incr : Symbol(incr, Decl(callChain.ts, 30, 57))
+257
View File
@@ -0,0 +1,257 @@
=== tests/cases/conformance/expressions/optionalChaining/callChain/callChain.ts ===
declare const o1: undefined | ((...args: any[]) => number);
>o1 : ((...args: any[]) => number) | undefined
>args : any[]
o1?.();
>o1?.() : number | undefined
>o1 : ((...args: any[]) => number) | undefined
o1?.(1);
>o1?.(1) : number | undefined
>o1 : ((...args: any[]) => number) | undefined
>1 : 1
o1?.(...[1, 2]);
>o1?.(...[1, 2]) : number | undefined
>o1 : ((...args: any[]) => number) | undefined
>...[1, 2] : number
>[1, 2] : number[]
>1 : 1
>2 : 2
o1?.(1, ...[2, 3], 4);
>o1?.(1, ...[2, 3], 4) : number | undefined
>o1 : ((...args: any[]) => number) | undefined
>1 : 1
>...[2, 3] : number
>[2, 3] : number[]
>2 : 2
>3 : 3
>4 : 4
declare const o2: undefined | { b: (...args: any[]) => number };
>o2 : { b: (...args: any[]) => number; } | undefined
>b : (...args: any[]) => number
>args : any[]
o2?.b();
>o2?.b() : number | undefined
>o2?.b : ((...args: any[]) => number) | undefined
>o2 : { b: (...args: any[]) => number; } | undefined
>b : ((...args: any[]) => number) | undefined
o2?.b(1);
>o2?.b(1) : number | undefined
>o2?.b : ((...args: any[]) => number) | undefined
>o2 : { b: (...args: any[]) => number; } | undefined
>b : ((...args: any[]) => number) | undefined
>1 : 1
o2?.b(...[1, 2]);
>o2?.b(...[1, 2]) : number | undefined
>o2?.b : ((...args: any[]) => number) | undefined
>o2 : { b: (...args: any[]) => number; } | undefined
>b : ((...args: any[]) => number) | undefined
>...[1, 2] : number
>[1, 2] : number[]
>1 : 1
>2 : 2
o2?.b(1, ...[2, 3], 4);
>o2?.b(1, ...[2, 3], 4) : number | undefined
>o2?.b : ((...args: any[]) => number) | undefined
>o2 : { b: (...args: any[]) => number; } | undefined
>b : ((...args: any[]) => number) | undefined
>1 : 1
>...[2, 3] : number
>[2, 3] : number[]
>2 : 2
>3 : 3
>4 : 4
o2?.["b"]();
>o2?.["b"]() : number | undefined
>o2?.["b"] : ((...args: any[]) => number) | undefined
>o2 : { b: (...args: any[]) => number; } | undefined
>"b" : "b"
o2?.["b"](1);
>o2?.["b"](1) : number | undefined
>o2?.["b"] : ((...args: any[]) => number) | undefined
>o2 : { b: (...args: any[]) => number; } | undefined
>"b" : "b"
>1 : 1
o2?.["b"](...[1, 2]);
>o2?.["b"](...[1, 2]) : number | undefined
>o2?.["b"] : ((...args: any[]) => number) | undefined
>o2 : { b: (...args: any[]) => number; } | undefined
>"b" : "b"
>...[1, 2] : number
>[1, 2] : number[]
>1 : 1
>2 : 2
o2?.["b"](1, ...[2, 3], 4);
>o2?.["b"](1, ...[2, 3], 4) : number | undefined
>o2?.["b"] : ((...args: any[]) => number) | undefined
>o2 : { b: (...args: any[]) => number; } | undefined
>"b" : "b"
>1 : 1
>...[2, 3] : number
>[2, 3] : number[]
>2 : 2
>3 : 3
>4 : 4
declare const o3: { b: ((...args: any[]) => { c: string }) | undefined };
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>b : ((...args: any[]) => { c: string; }) | undefined
>args : any[]
>c : string
o3.b?.().c;
>o3.b?.().c : string | undefined
>o3.b?.() : { c: string; } | undefined
>o3.b : ((...args: any[]) => { c: string; }) | undefined
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>b : ((...args: any[]) => { c: string; }) | undefined
>c : string | undefined
o3.b?.(1).c;
>o3.b?.(1).c : string | undefined
>o3.b?.(1) : { c: string; } | undefined
>o3.b : ((...args: any[]) => { c: string; }) | undefined
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>b : ((...args: any[]) => { c: string; }) | undefined
>1 : 1
>c : string | undefined
o3.b?.(...[1, 2]).c;
>o3.b?.(...[1, 2]).c : string | undefined
>o3.b?.(...[1, 2]) : { c: string; } | undefined
>o3.b : ((...args: any[]) => { c: string; }) | undefined
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>b : ((...args: any[]) => { c: string; }) | undefined
>...[1, 2] : number
>[1, 2] : number[]
>1 : 1
>2 : 2
>c : string | undefined
o3.b?.(1, ...[2, 3], 4).c;
>o3.b?.(1, ...[2, 3], 4).c : string | undefined
>o3.b?.(1, ...[2, 3], 4) : { c: string; } | undefined
>o3.b : ((...args: any[]) => { c: string; }) | undefined
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>b : ((...args: any[]) => { c: string; }) | undefined
>1 : 1
>...[2, 3] : number
>[2, 3] : number[]
>2 : 2
>3 : 3
>4 : 4
>c : string | undefined
o3.b?.()["c"];
>o3.b?.()["c"] : string | undefined
>o3.b?.() : { c: string; } | undefined
>o3.b : ((...args: any[]) => { c: string; }) | undefined
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>b : ((...args: any[]) => { c: string; }) | undefined
>"c" : "c"
o3.b?.(1)["c"];
>o3.b?.(1)["c"] : string | undefined
>o3.b?.(1) : { c: string; } | undefined
>o3.b : ((...args: any[]) => { c: string; }) | undefined
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>b : ((...args: any[]) => { c: string; }) | undefined
>1 : 1
>"c" : "c"
o3.b?.(...[1, 2])["c"];
>o3.b?.(...[1, 2])["c"] : string | undefined
>o3.b?.(...[1, 2]) : { c: string; } | undefined
>o3.b : ((...args: any[]) => { c: string; }) | undefined
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>b : ((...args: any[]) => { c: string; }) | undefined
>...[1, 2] : number
>[1, 2] : number[]
>1 : 1
>2 : 2
>"c" : "c"
o3.b?.(1, ...[2, 3], 4)["c"];
>o3.b?.(1, ...[2, 3], 4)["c"] : string | undefined
>o3.b?.(1, ...[2, 3], 4) : { c: string; } | undefined
>o3.b : ((...args: any[]) => { c: string; }) | undefined
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>b : ((...args: any[]) => { c: string; }) | undefined
>1 : 1
>...[2, 3] : number
>[2, 3] : number[]
>2 : 2
>3 : 3
>4 : 4
>"c" : "c"
o3["b"]?.().c;
>o3["b"]?.().c : string | undefined
>o3["b"]?.() : { c: string; } | undefined
>o3["b"] : ((...args: any[]) => { c: string; }) | undefined
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>"b" : "b"
>c : string | undefined
o3["b"]?.(1).c;
>o3["b"]?.(1).c : string | undefined
>o3["b"]?.(1) : { c: string; } | undefined
>o3["b"] : ((...args: any[]) => { c: string; }) | undefined
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>"b" : "b"
>1 : 1
>c : string | undefined
o3["b"]?.(...[1, 2]).c;
>o3["b"]?.(...[1, 2]).c : string | undefined
>o3["b"]?.(...[1, 2]) : { c: string; } | undefined
>o3["b"] : ((...args: any[]) => { c: string; }) | undefined
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>"b" : "b"
>...[1, 2] : number
>[1, 2] : number[]
>1 : 1
>2 : 2
>c : string | undefined
o3["b"]?.(1, ...[2, 3], 4).c;
>o3["b"]?.(1, ...[2, 3], 4).c : string | undefined
>o3["b"]?.(1, ...[2, 3], 4) : { c: string; } | undefined
>o3["b"] : ((...args: any[]) => { c: string; }) | undefined
>o3 : { b: ((...args: any[]) => { c: string; }) | undefined; }
>"b" : "b"
>1 : 1
>...[2, 3] : number
>[2, 3] : number[]
>2 : 2
>3 : 3
>4 : 4
>c : string | undefined
declare const o4: undefined | (<T>(f: (a: T) => T) => T);
>o4 : (<T>(f: (a: T) => T) => T) | undefined
>f : (a: T) => T
>a : T
declare function incr(x: number): number;
>incr : (x: number) => number
>x : number
const v: number | undefined = o4?.(incr);
>v : number | undefined
>o4?.(incr) : number | undefined
>o4 : (<T>(f: (a: T) => T) => T) | undefined
>incr : (x: number) => number
@@ -0,0 +1,230 @@
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(10,1): error TS2454: Variable 'a' is used before being assigned.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(14,1): error TS2454: Variable 'b' is used before being assigned.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(18,1): error TS2454: Variable 'c' is used before being assigned.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(22,1): error TS2454: Variable 'd' is used before being assigned.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(35,5): error TS2722: Cannot invoke an object which is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(39,1): error TS2722: Cannot invoke an object which is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(52,5): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(57,1): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(62,5): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(68,5): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(72,1): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(83,5): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(87,1): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(104,5): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(105,5): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(105,5): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(111,1): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(112,1): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(112,1): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(130,5): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(134,1): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(153,9): error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
==== tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts (22 errors) ====
// assignments in shortcutting chain
declare const o: undefined | {
[key: string]: any;
[key: number]: any;
(...args: any[]): any;
};
let a: number;
o?.[a = 1];
a.toString();
~
!!! error TS2454: Variable 'a' is used before being assigned.
let b: number;
o?.x[b = 1];
b.toString();
~
!!! error TS2454: Variable 'b' is used before being assigned.
let c: number;
o?.(c = 1)
c.toString();
~
!!! error TS2454: Variable 'c' is used before being assigned.
let d: number;
o?.x(d = 1);
d.toString();
~
!!! error TS2454: Variable 'd' is used before being assigned.
// type predicates
declare const f: undefined | ((x: any) => x is number);
declare const x: string | number;
if (f?.(x)) {
x; // number
f; // (x: any) => x is number
f(x);
}
else {
x;
f;
f(x);
~
!!! error TS2722: Cannot invoke an object which is possibly 'undefined'.
}
x;
f;
f(x);
~
!!! error TS2722: Cannot invoke an object which is possibly 'undefined'.
declare const o2: { f(x: any): x is number; } | undefined;
if (o2?.f(x)) {
x; // number
o2.f; // (x: any) => x is number
o2?.f;
o2?.f(x);
}
else {
x;
o2;
o2?.f;
o2.f;
~~
!!! error TS2532: Object is possibly 'undefined'.
}
x;
o2;
o2?.f;
o2.f;
~~
!!! error TS2532: Object is possibly 'undefined'.
declare const o3: { x: 1, y: string } | { x: 2, y: number } | undefined;
if (o3?.x === 1) {
o3; // TODO: should be `{ x: y, y: string }`
o3.x; // TODO: should not be an error.
~~
!!! error TS2532: Object is possibly 'undefined'.
o3?.x;
}
else {
o3;
o3?.x;
o3.x;
~~
!!! error TS2532: Object is possibly 'undefined'.
}
o3;
o3?.x;
o3.x;
~~
!!! error TS2532: Object is possibly 'undefined'.
declare const o4: { x?: { y: boolean } };
if (o4.x?.y) {
o4.x; // { y: boolean }
o4.x.y; // true
o4.x?.y; // true
}
else {
o4.x;
o4.x?.y;
o4.x.y;
~~~~
!!! error TS2532: Object is possibly 'undefined'.
}
o4.x;
o4.x?.y;
o4.x.y;
~~~~
!!! error TS2532: Object is possibly 'undefined'.
declare const o5: { x?: { y: { z?: { w: boolean } } } };
if (o5.x?.y.z?.w) {
o5.x;
o5.x.y;
o5.x.y.z;
o5.x.y.z.w; // true
o5.x.y.z?.w; // true
o5.x?.y.z.w; // true
o5.x?.y.z?.w; // true
}
else {
o5.x;
o5.x?.y;
o5.x?.y.z;
o5.x?.y.z?.w;
o5.x.y;
~~~~
!!! error TS2532: Object is possibly 'undefined'.
o5.x.y.z.w;
~~~~
!!! error TS2532: Object is possibly 'undefined'.
~~~~~~~~
!!! error TS2532: Object is possibly 'undefined'.
}
o5.x;
o5.x?.y;
o5.x?.y.z;
o5.x?.y.z?.w;
o5.x.y;
~~~~
!!! error TS2532: Object is possibly 'undefined'.
o5.x.y.z.w;
~~~~
!!! error TS2532: Object is possibly 'undefined'.
~~~~~~~~
!!! error TS2532: Object is possibly 'undefined'.
interface Base {
f(): this is Derived;
}
interface Derived extends Base {
x: number;
}
declare const o6: Base | undefined;
if (o6?.f()) {
o6; // Derived
o6.f;
}
else {
o6;
o6?.f;
o6.f;
~~
!!! error TS2532: Object is possibly 'undefined'.
}
o6;
o6?.f;
o6.f;
~~
!!! error TS2532: Object is possibly 'undefined'.
// asserts
declare const isDefined: <T>(value: T) => asserts value is NonNullable<T>;
declare const isString: (value: unknown) => asserts value is string;
declare const maybeIsString: undefined | ((value: unknown) => asserts value is string);
declare const maybeNever: undefined | (() => never);
function f01(x: unknown) {
if (!!true) {
isString?.(x);
x;
}
if (!!true) {
maybeIsString?.(x);
x;
}
if (!!true) {
isDefined(maybeIsString);
maybeIsString?.(x);
~~~~~~~~~~~~~
!!! error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
x;
}
if (!!true) {
maybeNever?.();
x;
}
}
@@ -0,0 +1,288 @@
//// [controlFlowOptionalChain.ts]
// assignments in shortcutting chain
declare const o: undefined | {
[key: string]: any;
[key: number]: any;
(...args: any[]): any;
};
let a: number;
o?.[a = 1];
a.toString();
let b: number;
o?.x[b = 1];
b.toString();
let c: number;
o?.(c = 1)
c.toString();
let d: number;
o?.x(d = 1);
d.toString();
// type predicates
declare const f: undefined | ((x: any) => x is number);
declare const x: string | number;
if (f?.(x)) {
x; // number
f; // (x: any) => x is number
f(x);
}
else {
x;
f;
f(x);
}
x;
f;
f(x);
declare const o2: { f(x: any): x is number; } | undefined;
if (o2?.f(x)) {
x; // number
o2.f; // (x: any) => x is number
o2?.f;
o2?.f(x);
}
else {
x;
o2;
o2?.f;
o2.f;
}
x;
o2;
o2?.f;
o2.f;
declare const o3: { x: 1, y: string } | { x: 2, y: number } | undefined;
if (o3?.x === 1) {
o3; // TODO: should be `{ x: y, y: string }`
o3.x; // TODO: should not be an error.
o3?.x;
}
else {
o3;
o3?.x;
o3.x;
}
o3;
o3?.x;
o3.x;
declare const o4: { x?: { y: boolean } };
if (o4.x?.y) {
o4.x; // { y: boolean }
o4.x.y; // true
o4.x?.y; // true
}
else {
o4.x;
o4.x?.y;
o4.x.y;
}
o4.x;
o4.x?.y;
o4.x.y;
declare const o5: { x?: { y: { z?: { w: boolean } } } };
if (o5.x?.y.z?.w) {
o5.x;
o5.x.y;
o5.x.y.z;
o5.x.y.z.w; // true
o5.x.y.z?.w; // true
o5.x?.y.z.w; // true
o5.x?.y.z?.w; // true
}
else {
o5.x;
o5.x?.y;
o5.x?.y.z;
o5.x?.y.z?.w;
o5.x.y;
o5.x.y.z.w;
}
o5.x;
o5.x?.y;
o5.x?.y.z;
o5.x?.y.z?.w;
o5.x.y;
o5.x.y.z.w;
interface Base {
f(): this is Derived;
}
interface Derived extends Base {
x: number;
}
declare const o6: Base | undefined;
if (o6?.f()) {
o6; // Derived
o6.f;
}
else {
o6;
o6?.f;
o6.f;
}
o6;
o6?.f;
o6.f;
// asserts
declare const isDefined: <T>(value: T) => asserts value is NonNullable<T>;
declare const isString: (value: unknown) => asserts value is string;
declare const maybeIsString: undefined | ((value: unknown) => asserts value is string);
declare const maybeNever: undefined | (() => never);
function f01(x: unknown) {
if (!!true) {
isString?.(x);
x;
}
if (!!true) {
maybeIsString?.(x);
x;
}
if (!!true) {
isDefined(maybeIsString);
maybeIsString?.(x);
x;
}
if (!!true) {
maybeNever?.();
x;
}
}
//// [controlFlowOptionalChain.js]
"use strict";
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10;
var a;
(_a = o) === null || _a === void 0 ? void 0 : _a[a = 1];
a.toString();
var b;
(_b = o) === null || _b === void 0 ? void 0 : _b.x[b = 1];
b.toString();
var c;
(_c = o) === null || _c === void 0 ? void 0 : _c(c = 1);
c.toString();
var d;
(_d = o) === null || _d === void 0 ? void 0 : _d.x(d = 1);
d.toString();
if ((_e = f) === null || _e === void 0 ? void 0 : _e(x)) {
x; // number
f; // (x: any) => x is number
f(x);
}
else {
x;
f;
f(x);
}
x;
f;
f(x);
if ((_f = o2) === null || _f === void 0 ? void 0 : _f.f(x)) {
x; // number
o2.f; // (x: any) => x is number
(_g = o2) === null || _g === void 0 ? void 0 : _g.f;
(_h = o2) === null || _h === void 0 ? void 0 : _h.f(x);
}
else {
x;
o2;
(_j = o2) === null || _j === void 0 ? void 0 : _j.f;
o2.f;
}
x;
o2;
(_k = o2) === null || _k === void 0 ? void 0 : _k.f;
o2.f;
if (((_l = o3) === null || _l === void 0 ? void 0 : _l.x) === 1) {
o3; // TODO: should be `{ x: y, y: string }`
o3.x; // TODO: should not be an error.
(_m = o3) === null || _m === void 0 ? void 0 : _m.x;
}
else {
o3;
(_o = o3) === null || _o === void 0 ? void 0 : _o.x;
o3.x;
}
o3;
(_p = o3) === null || _p === void 0 ? void 0 : _p.x;
o3.x;
if ((_q = o4.x) === null || _q === void 0 ? void 0 : _q.y) {
o4.x; // { y: boolean }
o4.x.y; // true
(_r = o4.x) === null || _r === void 0 ? void 0 : _r.y; // true
}
else {
o4.x;
(_s = o4.x) === null || _s === void 0 ? void 0 : _s.y;
o4.x.y;
}
o4.x;
(_t = o4.x) === null || _t === void 0 ? void 0 : _t.y;
o4.x.y;
if ((_v = (_u = o5.x) === null || _u === void 0 ? void 0 : _u.y.z) === null || _v === void 0 ? void 0 : _v.w) {
o5.x;
o5.x.y;
o5.x.y.z;
o5.x.y.z.w; // true
(_w = o5.x.y.z) === null || _w === void 0 ? void 0 : _w.w; // true
(_x = o5.x) === null || _x === void 0 ? void 0 : _x.y.z.w; // true
(_z = (_y = o5.x) === null || _y === void 0 ? void 0 : _y.y.z) === null || _z === void 0 ? void 0 : _z.w; // true
}
else {
o5.x;
(_0 = o5.x) === null || _0 === void 0 ? void 0 : _0.y;
(_1 = o5.x) === null || _1 === void 0 ? void 0 : _1.y.z;
(_3 = (_2 = o5.x) === null || _2 === void 0 ? void 0 : _2.y.z) === null || _3 === void 0 ? void 0 : _3.w;
o5.x.y;
o5.x.y.z.w;
}
o5.x;
(_4 = o5.x) === null || _4 === void 0 ? void 0 : _4.y;
(_5 = o5.x) === null || _5 === void 0 ? void 0 : _5.y.z;
(_7 = (_6 = o5.x) === null || _6 === void 0 ? void 0 : _6.y.z) === null || _7 === void 0 ? void 0 : _7.w;
o5.x.y;
o5.x.y.z.w;
if ((_8 = o6) === null || _8 === void 0 ? void 0 : _8.f()) {
o6; // Derived
o6.f;
}
else {
o6;
(_9 = o6) === null || _9 === void 0 ? void 0 : _9.f;
o6.f;
}
o6;
(_10 = o6) === null || _10 === void 0 ? void 0 : _10.f;
o6.f;
function f01(x) {
var _a, _b, _c, _d;
if (!!true) {
(_a = isString) === null || _a === void 0 ? void 0 : _a(x);
x;
}
if (!!true) {
(_b = maybeIsString) === null || _b === void 0 ? void 0 : _b(x);
x;
}
if (!!true) {
isDefined(maybeIsString);
(_c = maybeIsString) === null || _c === void 0 ? void 0 : _c(x);
x;
}
if (!!true) {
(_d = maybeNever) === null || _d === void 0 ? void 0 : _d();
x;
}
}
@@ -0,0 +1,602 @@
=== tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts ===
// assignments in shortcutting chain
declare const o: undefined | {
>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 1, 13))
[key: string]: any;
>key : Symbol(key, Decl(controlFlowOptionalChain.ts, 2, 5))
[key: number]: any;
>key : Symbol(key, Decl(controlFlowOptionalChain.ts, 3, 5))
(...args: any[]): any;
>args : Symbol(args, Decl(controlFlowOptionalChain.ts, 4, 5))
};
let a: number;
>a : Symbol(a, Decl(controlFlowOptionalChain.ts, 7, 3))
o?.[a = 1];
>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 1, 13))
>a : Symbol(a, Decl(controlFlowOptionalChain.ts, 7, 3))
a.toString();
>a.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
>a : Symbol(a, Decl(controlFlowOptionalChain.ts, 7, 3))
>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
let b: number;
>b : Symbol(b, Decl(controlFlowOptionalChain.ts, 11, 3))
o?.x[b = 1];
>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 1, 13))
>b : Symbol(b, Decl(controlFlowOptionalChain.ts, 11, 3))
b.toString();
>b.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
>b : Symbol(b, Decl(controlFlowOptionalChain.ts, 11, 3))
>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
let c: number;
>c : Symbol(c, Decl(controlFlowOptionalChain.ts, 15, 3))
o?.(c = 1)
>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 1, 13))
>c : Symbol(c, Decl(controlFlowOptionalChain.ts, 15, 3))
c.toString();
>c.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
>c : Symbol(c, Decl(controlFlowOptionalChain.ts, 15, 3))
>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
let d: number;
>d : Symbol(d, Decl(controlFlowOptionalChain.ts, 19, 3))
o?.x(d = 1);
>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 1, 13))
>d : Symbol(d, Decl(controlFlowOptionalChain.ts, 19, 3))
d.toString();
>d.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
>d : Symbol(d, Decl(controlFlowOptionalChain.ts, 19, 3))
>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
// type predicates
declare const f: undefined | ((x: any) => x is number);
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 24, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 24, 31))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 24, 31))
declare const x: string | number;
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
if (f?.(x)) {
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 24, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
x; // number
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
f; // (x: any) => x is number
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 24, 13))
f(x);
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 24, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
}
else {
x;
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
f;
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 24, 13))
f(x);
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 24, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
}
x;
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
f;
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 24, 13))
f(x);
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 24, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
declare const o2: { f(x: any): x is number; } | undefined;
>o2 : Symbol(o2, Decl(controlFlowOptionalChain.ts, 40, 13))
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 40, 22))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 40, 22))
if (o2?.f(x)) {
>o2?.f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
>o2 : Symbol(o2, Decl(controlFlowOptionalChain.ts, 40, 13))
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
x; // number
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
o2.f; // (x: any) => x is number
>o2.f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
>o2 : Symbol(o2, Decl(controlFlowOptionalChain.ts, 40, 13))
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
o2?.f;
>o2?.f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
>o2 : Symbol(o2, Decl(controlFlowOptionalChain.ts, 40, 13))
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
o2?.f(x);
>o2?.f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
>o2 : Symbol(o2, Decl(controlFlowOptionalChain.ts, 40, 13))
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
}
else {
x;
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
o2;
>o2 : Symbol(o2, Decl(controlFlowOptionalChain.ts, 40, 13))
o2?.f;
>o2?.f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
>o2 : Symbol(o2, Decl(controlFlowOptionalChain.ts, 40, 13))
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
o2.f;
>o2.f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
>o2 : Symbol(o2, Decl(controlFlowOptionalChain.ts, 40, 13))
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
}
x;
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 25, 13))
o2;
>o2 : Symbol(o2, Decl(controlFlowOptionalChain.ts, 40, 13))
o2?.f;
>o2?.f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
>o2 : Symbol(o2, Decl(controlFlowOptionalChain.ts, 40, 13))
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
o2.f;
>o2.f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
>o2 : Symbol(o2, Decl(controlFlowOptionalChain.ts, 40, 13))
>f : Symbol(f, Decl(controlFlowOptionalChain.ts, 40, 19))
declare const o3: { x: 1, y: string } | { x: 2, y: number } | undefined;
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 58, 25))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 41))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 58, 47))
if (o3?.x === 1) {
>o3?.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
o3; // TODO: should be `{ x: y, y: string }`
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
o3.x; // TODO: should not be an error.
>o3.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
o3?.x;
>o3?.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
}
else {
o3;
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
o3?.x;
>o3?.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
o3.x;
>o3.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
}
o3;
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
o3?.x;
>o3?.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
o3.x;
>o3.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
>o3 : Symbol(o3, Decl(controlFlowOptionalChain.ts, 58, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 58, 19), Decl(controlFlowOptionalChain.ts, 58, 41))
declare const o4: { x?: { y: boolean } };
>o4 : Symbol(o4, Decl(controlFlowOptionalChain.ts, 73, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
if (o4.x?.y) {
>o4.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
>o4.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>o4 : Symbol(o4, Decl(controlFlowOptionalChain.ts, 73, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
o4.x; // { y: boolean }
>o4.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>o4 : Symbol(o4, Decl(controlFlowOptionalChain.ts, 73, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
o4.x.y; // true
>o4.x.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
>o4.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>o4 : Symbol(o4, Decl(controlFlowOptionalChain.ts, 73, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
o4.x?.y; // true
>o4.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
>o4.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>o4 : Symbol(o4, Decl(controlFlowOptionalChain.ts, 73, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
}
else {
o4.x;
>o4.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>o4 : Symbol(o4, Decl(controlFlowOptionalChain.ts, 73, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
o4.x?.y;
>o4.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
>o4.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>o4 : Symbol(o4, Decl(controlFlowOptionalChain.ts, 73, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
o4.x.y;
>o4.x.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
>o4.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>o4 : Symbol(o4, Decl(controlFlowOptionalChain.ts, 73, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
}
o4.x;
>o4.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>o4 : Symbol(o4, Decl(controlFlowOptionalChain.ts, 73, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
o4.x?.y;
>o4.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
>o4.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>o4 : Symbol(o4, Decl(controlFlowOptionalChain.ts, 73, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
o4.x.y;
>o4.x.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
>o4.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>o4 : Symbol(o4, Decl(controlFlowOptionalChain.ts, 73, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 73, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 73, 25))
declare const o5: { x?: { y: { z?: { w: boolean } } } };
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
if (o5.x?.y.z?.w) {
>o5.x?.y.z?.w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
>o5.x?.y.z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>o5.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
o5.x;
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
o5.x.y;
>o5.x.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
o5.x.y.z;
>o5.x.y.z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>o5.x.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
o5.x.y.z.w; // true
>o5.x.y.z.w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
>o5.x.y.z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>o5.x.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
o5.x.y.z?.w; // true
>o5.x.y.z?.w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
>o5.x.y.z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>o5.x.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
o5.x?.y.z.w; // true
>o5.x?.y.z.w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
>o5.x?.y.z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>o5.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
o5.x?.y.z?.w; // true
>o5.x?.y.z?.w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
>o5.x?.y.z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>o5.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
}
else {
o5.x;
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
o5.x?.y;
>o5.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
o5.x?.y.z;
>o5.x?.y.z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>o5.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
o5.x?.y.z?.w;
>o5.x?.y.z?.w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
>o5.x?.y.z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>o5.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
o5.x.y;
>o5.x.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
o5.x.y.z.w;
>o5.x.y.z.w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
>o5.x.y.z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>o5.x.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
}
o5.x;
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
o5.x?.y;
>o5.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
o5.x?.y.z;
>o5.x?.y.z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>o5.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
o5.x?.y.z?.w;
>o5.x?.y.z?.w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
>o5.x?.y.z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>o5.x?.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
o5.x.y;
>o5.x.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
o5.x.y.z.w;
>o5.x.y.z.w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
>o5.x.y.z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>o5.x.y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>o5.x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>o5 : Symbol(o5, Decl(controlFlowOptionalChain.ts, 88, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 88, 19))
>y : Symbol(y, Decl(controlFlowOptionalChain.ts, 88, 25))
>z : Symbol(z, Decl(controlFlowOptionalChain.ts, 88, 30))
>w : Symbol(w, Decl(controlFlowOptionalChain.ts, 88, 36))
interface Base {
>Base : Symbol(Base, Decl(controlFlowOptionalChain.ts, 111, 11))
f(): this is Derived;
>f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
>Derived : Symbol(Derived, Decl(controlFlowOptionalChain.ts, 115, 1))
}
interface Derived extends Base {
>Derived : Symbol(Derived, Decl(controlFlowOptionalChain.ts, 115, 1))
>Base : Symbol(Base, Decl(controlFlowOptionalChain.ts, 111, 11))
x: number;
>x : Symbol(Derived.x, Decl(controlFlowOptionalChain.ts, 117, 32))
}
declare const o6: Base | undefined;
>o6 : Symbol(o6, Decl(controlFlowOptionalChain.ts, 121, 13))
>Base : Symbol(Base, Decl(controlFlowOptionalChain.ts, 111, 11))
if (o6?.f()) {
>o6?.f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
>o6 : Symbol(o6, Decl(controlFlowOptionalChain.ts, 121, 13))
>f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
o6; // Derived
>o6 : Symbol(o6, Decl(controlFlowOptionalChain.ts, 121, 13))
o6.f;
>o6.f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
>o6 : Symbol(o6, Decl(controlFlowOptionalChain.ts, 121, 13))
>f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
}
else {
o6;
>o6 : Symbol(o6, Decl(controlFlowOptionalChain.ts, 121, 13))
o6?.f;
>o6?.f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
>o6 : Symbol(o6, Decl(controlFlowOptionalChain.ts, 121, 13))
>f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
o6.f;
>o6.f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
>o6 : Symbol(o6, Decl(controlFlowOptionalChain.ts, 121, 13))
>f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
}
o6;
>o6 : Symbol(o6, Decl(controlFlowOptionalChain.ts, 121, 13))
o6?.f;
>o6?.f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
>o6 : Symbol(o6, Decl(controlFlowOptionalChain.ts, 121, 13))
>f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
o6.f;
>o6.f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
>o6 : Symbol(o6, Decl(controlFlowOptionalChain.ts, 121, 13))
>f : Symbol(Base.f, Decl(controlFlowOptionalChain.ts, 113, 16))
// asserts
declare const isDefined: <T>(value: T) => asserts value is NonNullable<T>;
>isDefined : Symbol(isDefined, Decl(controlFlowOptionalChain.ts, 136, 13))
>T : Symbol(T, Decl(controlFlowOptionalChain.ts, 136, 26))
>value : Symbol(value, Decl(controlFlowOptionalChain.ts, 136, 29))
>T : Symbol(T, Decl(controlFlowOptionalChain.ts, 136, 26))
>value : Symbol(value, Decl(controlFlowOptionalChain.ts, 136, 29))
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(controlFlowOptionalChain.ts, 136, 26))
declare const isString: (value: unknown) => asserts value is string;
>isString : Symbol(isString, Decl(controlFlowOptionalChain.ts, 137, 13))
>value : Symbol(value, Decl(controlFlowOptionalChain.ts, 137, 25))
>value : Symbol(value, Decl(controlFlowOptionalChain.ts, 137, 25))
declare const maybeIsString: undefined | ((value: unknown) => asserts value is string);
>maybeIsString : Symbol(maybeIsString, Decl(controlFlowOptionalChain.ts, 138, 13))
>value : Symbol(value, Decl(controlFlowOptionalChain.ts, 138, 43))
>value : Symbol(value, Decl(controlFlowOptionalChain.ts, 138, 43))
declare const maybeNever: undefined | (() => never);
>maybeNever : Symbol(maybeNever, Decl(controlFlowOptionalChain.ts, 139, 13))
function f01(x: unknown) {
>f01 : Symbol(f01, Decl(controlFlowOptionalChain.ts, 139, 52))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 141, 13))
if (!!true) {
isString?.(x);
>isString : Symbol(isString, Decl(controlFlowOptionalChain.ts, 137, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 141, 13))
x;
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 141, 13))
}
if (!!true) {
maybeIsString?.(x);
>maybeIsString : Symbol(maybeIsString, Decl(controlFlowOptionalChain.ts, 138, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 141, 13))
x;
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 141, 13))
}
if (!!true) {
isDefined(maybeIsString);
>isDefined : Symbol(isDefined, Decl(controlFlowOptionalChain.ts, 136, 13))
>maybeIsString : Symbol(maybeIsString, Decl(controlFlowOptionalChain.ts, 138, 13))
maybeIsString?.(x);
>maybeIsString : Symbol(maybeIsString, Decl(controlFlowOptionalChain.ts, 138, 13))
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 141, 13))
x;
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 141, 13))
}
if (!!true) {
maybeNever?.();
>maybeNever : Symbol(maybeNever, Decl(controlFlowOptionalChain.ts, 139, 13))
x;
>x : Symbol(x, Decl(controlFlowOptionalChain.ts, 141, 13))
}
}
@@ -0,0 +1,636 @@
=== tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts ===
// assignments in shortcutting chain
declare const o: undefined | {
>o : { (...args: any[]): any; [key: string]: any; [key: number]: any; } | undefined
[key: string]: any;
>key : string
[key: number]: any;
>key : number
(...args: any[]): any;
>args : any[]
};
let a: number;
>a : number
o?.[a = 1];
>o?.[a = 1] : any
>o : { (...args: any[]): any; [key: string]: any; [key: number]: any; } | undefined
>a = 1 : 1
>a : number
>1 : 1
a.toString();
>a.toString() : string
>a.toString : (radix?: number | undefined) => string
>a : number
>toString : (radix?: number | undefined) => string
let b: number;
>b : number
o?.x[b = 1];
>o?.x[b = 1] : any
>o?.x : any
>o : { (...args: any[]): any; [key: string]: any; [key: number]: any; } | undefined
>x : any
>b = 1 : 1
>b : number
>1 : 1
b.toString();
>b.toString() : string
>b.toString : (radix?: number | undefined) => string
>b : number
>toString : (radix?: number | undefined) => string
let c: number;
>c : number
o?.(c = 1)
>o?.(c = 1) : any
>o : { (...args: any[]): any; [key: string]: any; [key: number]: any; } | undefined
>c = 1 : 1
>c : number
>1 : 1
c.toString();
>c.toString() : string
>c.toString : (radix?: number | undefined) => string
>c : number
>toString : (radix?: number | undefined) => string
let d: number;
>d : number
o?.x(d = 1);
>o?.x(d = 1) : any
>o?.x : any
>o : { (...args: any[]): any; [key: string]: any; [key: number]: any; } | undefined
>x : any
>d = 1 : 1
>d : number
>1 : 1
d.toString();
>d.toString() : string
>d.toString : (radix?: number | undefined) => string
>d : number
>toString : (radix?: number | undefined) => string
// type predicates
declare const f: undefined | ((x: any) => x is number);
>f : ((x: any) => x is number) | undefined
>x : any
declare const x: string | number;
>x : string | number
if (f?.(x)) {
>f?.(x) : boolean | undefined
>f : ((x: any) => x is number) | undefined
>x : string | number
x; // number
>x : number
f; // (x: any) => x is number
>f : (x: any) => x is number
f(x);
>f(x) : boolean
>f : (x: any) => x is number
>x : number
}
else {
x;
>x : string | number
f;
>f : ((x: any) => x is number) | undefined
f(x);
>f(x) : boolean
>f : ((x: any) => x is number) | undefined
>x : string | number
}
x;
>x : string | number
f;
>f : ((x: any) => x is number) | undefined
f(x);
>f(x) : boolean
>f : ((x: any) => x is number) | undefined
>x : string | number
declare const o2: { f(x: any): x is number; } | undefined;
>o2 : { f(x: any): x is number; } | undefined
>f : (x: any) => x is number
>x : any
if (o2?.f(x)) {
>o2?.f(x) : boolean | undefined
>o2?.f : ((x: any) => x is number) | undefined
>o2 : { f(x: any): x is number; } | undefined
>f : ((x: any) => x is number) | undefined
>x : string | number
x; // number
>x : number
o2.f; // (x: any) => x is number
>o2.f : (x: any) => x is number
>o2 : { f(x: any): x is number; }
>f : (x: any) => x is number
o2?.f;
>o2?.f : (x: any) => x is number
>o2 : { f(x: any): x is number; }
>f : (x: any) => x is number
o2?.f(x);
>o2?.f(x) : boolean
>o2?.f : (x: any) => x is number
>o2 : { f(x: any): x is number; }
>f : (x: any) => x is number
>x : number
}
else {
x;
>x : string | number
o2;
>o2 : { f(x: any): x is number; } | undefined
o2?.f;
>o2?.f : ((x: any) => x is number) | undefined
>o2 : { f(x: any): x is number; } | undefined
>f : ((x: any) => x is number) | undefined
o2.f;
>o2.f : (x: any) => x is number
>o2 : { f(x: any): x is number; } | undefined
>f : (x: any) => x is number
}
x;
>x : string | number
o2;
>o2 : { f(x: any): x is number; } | undefined
o2?.f;
>o2?.f : ((x: any) => x is number) | undefined
>o2 : { f(x: any): x is number; } | undefined
>f : ((x: any) => x is number) | undefined
o2.f;
>o2.f : (x: any) => x is number
>o2 : { f(x: any): x is number; } | undefined
>f : (x: any) => x is number
declare const o3: { x: 1, y: string } | { x: 2, y: number } | undefined;
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
>x : 1
>y : string
>x : 2
>y : number
if (o3?.x === 1) {
>o3?.x === 1 : boolean
>o3?.x : 1 | 2 | undefined
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
>x : 1 | 2 | undefined
>1 : 1
o3; // TODO: should be `{ x: y, y: string }`
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
o3.x; // TODO: should not be an error.
>o3.x : 1
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
>x : 1
o3?.x;
>o3?.x : 1 | undefined
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
>x : 1 | undefined
}
else {
o3;
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
o3?.x;
>o3?.x : 2 | undefined
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
>x : 2 | undefined
o3.x;
>o3.x : 2
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
>x : 2
}
o3;
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
o3?.x;
>o3?.x : 1 | 2 | undefined
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
>x : 1 | 2 | undefined
o3.x;
>o3.x : 1 | 2
>o3 : { x: 1; y: string; } | { x: 2; y: number; } | undefined
>x : 1 | 2
declare const o4: { x?: { y: boolean } };
>o4 : { x?: { y: boolean; } | undefined; }
>x : { y: boolean; } | undefined
>y : boolean
if (o4.x?.y) {
>o4.x?.y : boolean | undefined
>o4.x : { y: boolean; } | undefined
>o4 : { x?: { y: boolean; } | undefined; }
>x : { y: boolean; } | undefined
>y : boolean | undefined
o4.x; // { y: boolean }
>o4.x : { y: boolean; }
>o4 : { x?: { y: boolean; } | undefined; }
>x : { y: boolean; }
o4.x.y; // true
>o4.x.y : true
>o4.x : { y: boolean; }
>o4 : { x?: { y: boolean; } | undefined; }
>x : { y: boolean; }
>y : true
o4.x?.y; // true
>o4.x?.y : true
>o4.x : { y: boolean; }
>o4 : { x?: { y: boolean; } | undefined; }
>x : { y: boolean; }
>y : true
}
else {
o4.x;
>o4.x : { y: boolean; } | undefined
>o4 : { x?: { y: boolean; } | undefined; }
>x : { y: boolean; } | undefined
o4.x?.y;
>o4.x?.y : boolean | undefined
>o4.x : { y: boolean; } | undefined
>o4 : { x?: { y: boolean; } | undefined; }
>x : { y: boolean; } | undefined
>y : boolean | undefined
o4.x.y;
>o4.x.y : boolean
>o4.x : { y: boolean; } | undefined
>o4 : { x?: { y: boolean; } | undefined; }
>x : { y: boolean; } | undefined
>y : boolean
}
o4.x;
>o4.x : { y: boolean; } | undefined
>o4 : { x?: { y: boolean; } | undefined; }
>x : { y: boolean; } | undefined
o4.x?.y;
>o4.x?.y : boolean | undefined
>o4.x : { y: boolean; } | undefined
>o4 : { x?: { y: boolean; } | undefined; }
>x : { y: boolean; } | undefined
>y : boolean | undefined
o4.x.y;
>o4.x.y : boolean
>o4.x : { y: boolean; } | undefined
>o4 : { x?: { y: boolean; } | undefined; }
>x : { y: boolean; } | undefined
>y : boolean
declare const o5: { x?: { y: { z?: { w: boolean } } } };
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>y : { z?: { w: boolean; } | undefined; }
>z : { w: boolean; } | undefined
>w : boolean
if (o5.x?.y.z?.w) {
>o5.x?.y.z?.w : boolean | undefined
>o5.x?.y.z : { w: boolean; } | undefined
>o5.x?.y : { z?: { w: boolean; } | undefined; } | undefined
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>y : { z?: { w: boolean; } | undefined; } | undefined
>z : { w: boolean; } | undefined
>w : boolean | undefined
o5.x;
>o5.x : { y: { z?: { w: boolean; } | undefined; }; }
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; }
o5.x.y;
>o5.x.y : { z?: { w: boolean; } | undefined; }
>o5.x : { y: { z?: { w: boolean; } | undefined; }; }
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; }
>y : { z?: { w: boolean; } | undefined; }
o5.x.y.z;
>o5.x.y.z : { w: boolean; }
>o5.x.y : { z?: { w: boolean; } | undefined; }
>o5.x : { y: { z?: { w: boolean; } | undefined; }; }
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; }
>y : { z?: { w: boolean; } | undefined; }
>z : { w: boolean; }
o5.x.y.z.w; // true
>o5.x.y.z.w : true
>o5.x.y.z : { w: boolean; }
>o5.x.y : { z?: { w: boolean; } | undefined; }
>o5.x : { y: { z?: { w: boolean; } | undefined; }; }
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; }
>y : { z?: { w: boolean; } | undefined; }
>z : { w: boolean; }
>w : true
o5.x.y.z?.w; // true
>o5.x.y.z?.w : true
>o5.x.y.z : { w: boolean; }
>o5.x.y : { z?: { w: boolean; } | undefined; }
>o5.x : { y: { z?: { w: boolean; } | undefined; }; }
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; }
>y : { z?: { w: boolean; } | undefined; }
>z : { w: boolean; }
>w : true
o5.x?.y.z.w; // true
>o5.x?.y.z.w : true
>o5.x?.y.z : { w: boolean; }
>o5.x?.y : { z?: { w: boolean; } | undefined; }
>o5.x : { y: { z?: { w: boolean; } | undefined; }; }
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; }
>y : { z?: { w: boolean; } | undefined; }
>z : { w: boolean; }
>w : true
o5.x?.y.z?.w; // true
>o5.x?.y.z?.w : true
>o5.x?.y.z : { w: boolean; }
>o5.x?.y : { z?: { w: boolean; } | undefined; }
>o5.x : { y: { z?: { w: boolean; } | undefined; }; }
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; }
>y : { z?: { w: boolean; } | undefined; }
>z : { w: boolean; }
>w : true
}
else {
o5.x;
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
o5.x?.y;
>o5.x?.y : { z?: { w: boolean; } | undefined; } | undefined
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>y : { z?: { w: boolean; } | undefined; } | undefined
o5.x?.y.z;
>o5.x?.y.z : { w: boolean; } | undefined
>o5.x?.y : { z?: { w: boolean; } | undefined; } | undefined
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>y : { z?: { w: boolean; } | undefined; } | undefined
>z : { w: boolean; } | undefined
o5.x?.y.z?.w;
>o5.x?.y.z?.w : boolean | undefined
>o5.x?.y.z : { w: boolean; } | undefined
>o5.x?.y : { z?: { w: boolean; } | undefined; } | undefined
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>y : { z?: { w: boolean; } | undefined; } | undefined
>z : { w: boolean; } | undefined
>w : boolean | undefined
o5.x.y;
>o5.x.y : { z?: { w: boolean; } | undefined; }
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>y : { z?: { w: boolean; } | undefined; }
o5.x.y.z.w;
>o5.x.y.z.w : boolean
>o5.x.y.z : { w: boolean; } | undefined
>o5.x.y : { z?: { w: boolean; } | undefined; }
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>y : { z?: { w: boolean; } | undefined; }
>z : { w: boolean; } | undefined
>w : boolean
}
o5.x;
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
o5.x?.y;
>o5.x?.y : { z?: { w: boolean; } | undefined; } | undefined
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>y : { z?: { w: boolean; } | undefined; } | undefined
o5.x?.y.z;
>o5.x?.y.z : { w: boolean; } | undefined
>o5.x?.y : { z?: { w: boolean; } | undefined; } | undefined
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>y : { z?: { w: boolean; } | undefined; } | undefined
>z : { w: boolean; } | undefined
o5.x?.y.z?.w;
>o5.x?.y.z?.w : boolean | undefined
>o5.x?.y.z : { w: boolean; } | undefined
>o5.x?.y : { z?: { w: boolean; } | undefined; } | undefined
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>y : { z?: { w: boolean; } | undefined; } | undefined
>z : { w: boolean; } | undefined
>w : boolean | undefined
o5.x.y;
>o5.x.y : { z?: { w: boolean; } | undefined; }
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>y : { z?: { w: boolean; } | undefined; }
o5.x.y.z.w;
>o5.x.y.z.w : boolean
>o5.x.y.z : { w: boolean; } | undefined
>o5.x.y : { z?: { w: boolean; } | undefined; }
>o5.x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>o5 : { x?: { y: { z?: { w: boolean; } | undefined; }; } | undefined; }
>x : { y: { z?: { w: boolean; } | undefined; }; } | undefined
>y : { z?: { w: boolean; } | undefined; }
>z : { w: boolean; } | undefined
>w : boolean
interface Base {
f(): this is Derived;
>f : () => this is Derived
}
interface Derived extends Base {
x: number;
>x : number
}
declare const o6: Base | undefined;
>o6 : Base | undefined
if (o6?.f()) {
>o6?.f() : boolean | undefined
>o6?.f : (() => this is Derived) | undefined
>o6 : Base | undefined
>f : (() => this is Derived) | undefined
o6; // Derived
>o6 : Derived
o6.f;
>o6.f : () => this is Derived
>o6 : Derived
>f : () => this is Derived
}
else {
o6;
>o6 : Base | undefined
o6?.f;
>o6?.f : (() => this is Derived) | undefined
>o6 : Base | undefined
>f : (() => this is Derived) | undefined
o6.f;
>o6.f : () => this is Derived
>o6 : Base | undefined
>f : () => this is Derived
}
o6;
>o6 : Base | undefined
o6?.f;
>o6?.f : (() => this is Derived) | undefined
>o6 : Base | undefined
>f : (() => this is Derived) | undefined
o6.f;
>o6.f : () => this is Derived
>o6 : Base | undefined
>f : () => this is Derived
// asserts
declare const isDefined: <T>(value: T) => asserts value is NonNullable<T>;
>isDefined : <T>(value: T) => asserts value is NonNullable<T>
>value : T
declare const isString: (value: unknown) => asserts value is string;
>isString : (value: unknown) => asserts value is string
>value : unknown
declare const maybeIsString: undefined | ((value: unknown) => asserts value is string);
>maybeIsString : ((value: unknown) => asserts value is string) | undefined
>value : unknown
declare const maybeNever: undefined | (() => never);
>maybeNever : (() => never) | undefined
function f01(x: unknown) {
>f01 : (x: unknown) => void
>x : unknown
if (!!true) {
>!!true : true
>!true : false
>true : true
isString?.(x);
>isString?.(x) : void
>isString : (value: unknown) => asserts value is string
>x : unknown
x;
>x : string
}
if (!!true) {
>!!true : true
>!true : false
>true : true
maybeIsString?.(x);
>maybeIsString?.(x) : void | undefined
>maybeIsString : ((value: unknown) => asserts value is string) | undefined
>x : unknown
x;
>x : unknown
}
if (!!true) {
>!!true : true
>!true : false
>true : true
isDefined(maybeIsString);
>isDefined(maybeIsString) : void
>isDefined : <T>(value: T) => asserts value is NonNullable<T>
>maybeIsString : ((value: unknown) => asserts value is string) | undefined
maybeIsString?.(x);
>maybeIsString?.(x) : void
>maybeIsString : (value: unknown) => asserts value is string
>x : unknown
x;
>x : unknown
}
if (!!true) {
>!!true : true
>!true : false
>true : true
maybeNever?.();
>maybeNever?.() : undefined
>maybeNever : (() => never) | undefined
x;
>x : unknown
}
}
@@ -0,0 +1,20 @@
//// [elementAccessChain.2.ts]
declare const o1: undefined | { b: string };
o1?.["b"];
declare const o2: undefined | { b: { c: string } };
o2?.["b"].c;
o2?.b["c"];
declare const o3: { b: undefined | { c: string } };
o3["b"]?.c;
o3.b?.["c"];
//// [elementAccessChain.2.js]
var _a, _b, _c, _d, _e;
(_a = o1) === null || _a === void 0 ? void 0 : _a["b"];
(_b = o2) === null || _b === void 0 ? void 0 : _b["b"].c;
(_c = o2) === null || _c === void 0 ? void 0 : _c.b["c"];
(_d = o3["b"]) === null || _d === void 0 ? void 0 : _d.c;
(_e = o3.b) === null || _e === void 0 ? void 0 : _e["c"];
@@ -0,0 +1,43 @@
=== tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.2.ts ===
declare const o1: undefined | { b: string };
>o1 : Symbol(o1, Decl(elementAccessChain.2.ts, 0, 13))
>b : Symbol(b, Decl(elementAccessChain.2.ts, 0, 31))
o1?.["b"];
>o1 : Symbol(o1, Decl(elementAccessChain.2.ts, 0, 13))
>"b" : Symbol(b, Decl(elementAccessChain.2.ts, 0, 31))
declare const o2: undefined | { b: { c: string } };
>o2 : Symbol(o2, Decl(elementAccessChain.2.ts, 3, 13))
>b : Symbol(b, Decl(elementAccessChain.2.ts, 3, 31))
>c : Symbol(c, Decl(elementAccessChain.2.ts, 3, 36))
o2?.["b"].c;
>o2?.["b"].c : Symbol(c, Decl(elementAccessChain.2.ts, 3, 36))
>o2 : Symbol(o2, Decl(elementAccessChain.2.ts, 3, 13))
>"b" : Symbol(b, Decl(elementAccessChain.2.ts, 3, 31))
>c : Symbol(c, Decl(elementAccessChain.2.ts, 3, 36))
o2?.b["c"];
>o2?.b : Symbol(b, Decl(elementAccessChain.2.ts, 3, 31))
>o2 : Symbol(o2, Decl(elementAccessChain.2.ts, 3, 13))
>b : Symbol(b, Decl(elementAccessChain.2.ts, 3, 31))
>"c" : Symbol(c, Decl(elementAccessChain.2.ts, 3, 36))
declare const o3: { b: undefined | { c: string } };
>o3 : Symbol(o3, Decl(elementAccessChain.2.ts, 7, 13))
>b : Symbol(b, Decl(elementAccessChain.2.ts, 7, 19))
>c : Symbol(c, Decl(elementAccessChain.2.ts, 7, 36))
o3["b"]?.c;
>o3["b"]?.c : Symbol(c, Decl(elementAccessChain.2.ts, 7, 36))
>o3 : Symbol(o3, Decl(elementAccessChain.2.ts, 7, 13))
>"b" : Symbol(b, Decl(elementAccessChain.2.ts, 7, 19))
>c : Symbol(c, Decl(elementAccessChain.2.ts, 7, 36))
o3.b?.["c"];
>o3.b : Symbol(b, Decl(elementAccessChain.2.ts, 7, 19))
>o3 : Symbol(o3, Decl(elementAccessChain.2.ts, 7, 13))
>b : Symbol(b, Decl(elementAccessChain.2.ts, 7, 19))
>"c" : Symbol(c, Decl(elementAccessChain.2.ts, 7, 36))
@@ -0,0 +1,48 @@
=== tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.2.ts ===
declare const o1: undefined | { b: string };
>o1 : { b: string; }
>b : string
o1?.["b"];
>o1?.["b"] : string
>o1 : { b: string; }
>"b" : "b"
declare const o2: undefined | { b: { c: string } };
>o2 : { b: { c: string; }; }
>b : { c: string; }
>c : string
o2?.["b"].c;
>o2?.["b"].c : string
>o2?.["b"] : { c: string; }
>o2 : { b: { c: string; }; }
>"b" : "b"
>c : string
o2?.b["c"];
>o2?.b["c"] : string
>o2?.b : { c: string; }
>o2 : { b: { c: string; }; }
>b : { c: string; }
>"c" : "c"
declare const o3: { b: undefined | { c: string } };
>o3 : { b: { c: string; }; }
>b : { c: string; }
>c : string
o3["b"]?.c;
>o3["b"]?.c : string
>o3["b"] : { c: string; }
>o3 : { b: { c: string; }; }
>"b" : "b"
>c : string
o3.b?.["c"];
>o3.b?.["c"] : string
>o3.b : { c: string; }
>o3 : { b: { c: string; }; }
>b : { c: string; }
>"c" : "c"
@@ -0,0 +1,98 @@
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(3,1): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(4,1): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(5,1): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(6,1): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(8,3): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(9,3): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(10,3): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(11,3): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(13,1): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(14,1): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(15,1): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(16,1): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(18,6): error TS2780: The left-hand side of a 'for...in' statement may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(19,6): error TS2780: The left-hand side of a 'for...in' statement may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(20,6): error TS2781: The left-hand side of a 'for...of' statement may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(21,6): error TS2781: The left-hand side of a 'for...of' statement may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(23,7): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(24,7): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(25,7): error TS2778: The target of an object rest assignment may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(26,7): error TS2778: The target of an object rest assignment may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(27,5): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts(28,5): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
==== tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts (22 errors) ====
declare const obj: any;
obj?.["a"]++;
~~~~~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
obj?.a["b"]++;
~~~~~~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
obj?.["a"]--;
~~~~~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
obj?.a["b"]--;
~~~~~~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
++obj?.["a"];
~~~~~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
++obj?.a["b"];
~~~~~~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
--obj?.["a"];
~~~~~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
--obj?.a["b"];
~~~~~~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
obj?.["a"] = 1;
~~~~~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
obj?.a["b"] = 1;
~~~~~~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
obj?.["a"] += 1;
~~~~~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
obj?.a["b"] += 1;
~~~~~~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
for (obj?.["a"] in {});
~~~~~~~~~~
!!! error TS2780: The left-hand side of a 'for...in' statement may not be an optional property access.
for (obj?.a["b"] in {});
~~~~~~~~~~~
!!! error TS2780: The left-hand side of a 'for...in' statement may not be an optional property access.
for (obj?.["a"] of []);
~~~~~~~~~~
!!! error TS2781: The left-hand side of a 'for...of' statement may not be an optional property access.
for (obj?.a["b"] of []);
~~~~~~~~~~~
!!! error TS2781: The left-hand side of a 'for...of' statement may not be an optional property access.
({ a: obj?.["a"] } = { a: 1 });
~~~~~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
({ a: obj?.a["b"] } = { a: 1 });
~~~~~~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
({ ...obj?.["a"] } = { a: 1 });
~~~~~~~~~~
!!! error TS2778: The target of an object rest assignment may not be an optional property access.
({ ...obj?.a["b"] } = { a: 1 });
~~~~~~~~~~~
!!! error TS2778: The target of an object rest assignment may not be an optional property access.
[...obj?.["a"]] = [];
~~~~~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
[...obj?.a["b"]] = [];
~~~~~~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
@@ -0,0 +1,75 @@
//// [elementAccessChain.3.ts]
declare const obj: any;
obj?.["a"]++;
obj?.a["b"]++;
obj?.["a"]--;
obj?.a["b"]--;
++obj?.["a"];
++obj?.a["b"];
--obj?.["a"];
--obj?.a["b"];
obj?.["a"] = 1;
obj?.a["b"] = 1;
obj?.["a"] += 1;
obj?.a["b"] += 1;
for (obj?.["a"] in {});
for (obj?.a["b"] in {});
for (obj?.["a"] of []);
for (obj?.a["b"] of []);
({ a: obj?.["a"] } = { a: 1 });
({ a: obj?.a["b"] } = { a: 1 });
({ ...obj?.["a"] } = { a: 1 });
({ ...obj?.a["b"] } = { a: 1 });
[...obj?.["a"]] = [];
[...obj?.a["b"]] = [];
//// [elementAccessChain.3.js]
"use strict";
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
((_a = obj) === null || _a === void 0 ? void 0 : _a["a"])++;
((_b = obj) === null || _b === void 0 ? void 0 : _b.a["b"])++;
((_c = obj) === null || _c === void 0 ? void 0 : _c["a"])--;
((_d = obj) === null || _d === void 0 ? void 0 : _d.a["b"])--;
++((_e = obj) === null || _e === void 0 ? void 0 : _e["a"]);
++((_f = obj) === null || _f === void 0 ? void 0 : _f.a["b"]);
--((_g = obj) === null || _g === void 0 ? void 0 : _g["a"]);
--((_h = obj) === null || _h === void 0 ? void 0 : _h.a["b"]);
(_j = obj) === null || _j === void 0 ? void 0 : _j["a"] = 1;
(_k = obj) === null || _k === void 0 ? void 0 : _k.a["b"] = 1;
(_l = obj) === null || _l === void 0 ? void 0 : _l["a"] += 1;
(_m = obj) === null || _m === void 0 ? void 0 : _m.a["b"] += 1;
for ((_o = obj) === null || _o === void 0 ? void 0 : _o["a"] in {})
;
for ((_p = obj) === null || _p === void 0 ? void 0 : _p.a["b"] in {})
;
for (var _i = 0, _y = []; _i < _y.length; _i++) {
(_q = obj) === null || _q === void 0 ? void 0 : _q["a"] = _y[_i];
;
}
for (var _z = 0, _0 = []; _z < _0.length; _z++) {
(_r = obj) === null || _r === void 0 ? void 0 : _r.a["b"] = _0[_z];
;
}
((_s = obj) === null || _s === void 0 ? void 0 : _s["a"] = { a: 1 }.a);
((_t = obj) === null || _t === void 0 ? void 0 : _t.a["b"] = { a: 1 }.a);
((_u = obj) === null || _u === void 0 ? void 0 : _u["a"] = __rest({ a: 1 }, []));
((_v = obj) === null || _v === void 0 ? void 0 : _v.a["b"] = __rest({ a: 1 }, []));
(_w = obj) === null || _w === void 0 ? void 0 : _w["a"] = [].slice(0);
(_x = obj) === null || _x === void 0 ? void 0 : _x.a["b"] = [].slice(0);
@@ -0,0 +1,76 @@
=== tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts ===
declare const obj: any;
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
obj?.["a"]++;
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
obj?.a["b"]++;
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
obj?.["a"]--;
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
obj?.a["b"]--;
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
++obj?.["a"];
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
++obj?.a["b"];
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
--obj?.["a"];
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
--obj?.a["b"];
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
obj?.["a"] = 1;
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
obj?.a["b"] = 1;
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
obj?.["a"] += 1;
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
obj?.a["b"] += 1;
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
for (obj?.["a"] in {});
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
for (obj?.a["b"] in {});
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
for (obj?.["a"] of []);
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
for (obj?.a["b"] of []);
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
({ a: obj?.["a"] } = { a: 1 });
>a : Symbol(a, Decl(elementAccessChain.3.ts, 22, 2))
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
>a : Symbol(a, Decl(elementAccessChain.3.ts, 22, 22))
({ a: obj?.a["b"] } = { a: 1 });
>a : Symbol(a, Decl(elementAccessChain.3.ts, 23, 2))
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
>a : Symbol(a, Decl(elementAccessChain.3.ts, 23, 23))
({ ...obj?.["a"] } = { a: 1 });
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
>a : Symbol(a, Decl(elementAccessChain.3.ts, 24, 22))
({ ...obj?.a["b"] } = { a: 1 });
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
>a : Symbol(a, Decl(elementAccessChain.3.ts, 25, 23))
[...obj?.["a"]] = [];
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
[...obj?.a["b"]] = [];
>obj : Symbol(obj, Decl(elementAccessChain.3.ts, 0, 13))
@@ -0,0 +1,190 @@
=== tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.3.ts ===
declare const obj: any;
>obj : any
obj?.["a"]++;
>obj?.["a"]++ : number
>obj?.["a"] : any
>obj : any
>"a" : "a"
obj?.a["b"]++;
>obj?.a["b"]++ : number
>obj?.a["b"] : any
>obj?.a : any
>obj : any
>a : any
>"b" : "b"
obj?.["a"]--;
>obj?.["a"]-- : number
>obj?.["a"] : any
>obj : any
>"a" : "a"
obj?.a["b"]--;
>obj?.a["b"]-- : number
>obj?.a["b"] : any
>obj?.a : any
>obj : any
>a : any
>"b" : "b"
++obj?.["a"];
>++obj?.["a"] : number
>obj?.["a"] : any
>obj : any
>"a" : "a"
++obj?.a["b"];
>++obj?.a["b"] : number
>obj?.a["b"] : any
>obj?.a : any
>obj : any
>a : any
>"b" : "b"
--obj?.["a"];
>--obj?.["a"] : number
>obj?.["a"] : any
>obj : any
>"a" : "a"
--obj?.a["b"];
>--obj?.a["b"] : number
>obj?.a["b"] : any
>obj?.a : any
>obj : any
>a : any
>"b" : "b"
obj?.["a"] = 1;
>obj?.["a"] = 1 : 1
>obj?.["a"] : any
>obj : any
>"a" : "a"
>1 : 1
obj?.a["b"] = 1;
>obj?.a["b"] = 1 : 1
>obj?.a["b"] : any
>obj?.a : any
>obj : any
>a : any
>"b" : "b"
>1 : 1
obj?.["a"] += 1;
>obj?.["a"] += 1 : any
>obj?.["a"] : any
>obj : any
>"a" : "a"
>1 : 1
obj?.a["b"] += 1;
>obj?.a["b"] += 1 : any
>obj?.a["b"] : any
>obj?.a : any
>obj : any
>a : any
>"b" : "b"
>1 : 1
for (obj?.["a"] in {});
>obj?.["a"] : any
>obj : any
>"a" : "a"
>{} : {}
for (obj?.a["b"] in {});
>obj?.a["b"] : any
>obj?.a : any
>obj : any
>a : any
>"b" : "b"
>{} : {}
for (obj?.["a"] of []);
>obj?.["a"] : any
>obj : any
>"a" : "a"
>[] : never[]
for (obj?.a["b"] of []);
>obj?.a["b"] : any
>obj?.a : any
>obj : any
>a : any
>"b" : "b"
>[] : never[]
({ a: obj?.["a"] } = { a: 1 });
>({ a: obj?.["a"] } = { a: 1 }) : { a: number; }
>{ a: obj?.["a"] } = { a: 1 } : { a: number; }
>{ a: obj?.["a"] } : { a: any; }
>a : any
>obj?.["a"] : any
>obj : any
>"a" : "a"
>{ a: 1 } : { a: number; }
>a : number
>1 : 1
({ a: obj?.a["b"] } = { a: 1 });
>({ a: obj?.a["b"] } = { a: 1 }) : { a: number; }
>{ a: obj?.a["b"] } = { a: 1 } : { a: number; }
>{ a: obj?.a["b"] } : { a: any; }
>a : any
>obj?.a["b"] : any
>obj?.a : any
>obj : any
>a : any
>"b" : "b"
>{ a: 1 } : { a: number; }
>a : number
>1 : 1
({ ...obj?.["a"] } = { a: 1 });
>({ ...obj?.["a"] } = { a: 1 }) : { a: number; }
>{ ...obj?.["a"] } = { a: 1 } : { a: number; }
>{ ...obj?.["a"] } : any
>obj?.["a"] : any
>obj : any
>"a" : "a"
>{ a: 1 } : { a: number; }
>a : number
>1 : 1
({ ...obj?.a["b"] } = { a: 1 });
>({ ...obj?.a["b"] } = { a: 1 }) : { a: number; }
>{ ...obj?.a["b"] } = { a: 1 } : { a: number; }
>{ ...obj?.a["b"] } : any
>obj?.a["b"] : any
>obj?.a : any
>obj : any
>a : any
>"b" : "b"
>{ a: 1 } : { a: number; }
>a : number
>1 : 1
[...obj?.["a"]] = [];
>[...obj?.["a"]] = [] : never[]
>[...obj?.["a"]] : never[]
>...obj?.["a"] : any
>obj?.["a"] : any
>obj : any
>"a" : "a"
>[] : never[]
[...obj?.a["b"]] = [];
>[...obj?.a["b"]] = [] : never[]
>[...obj?.a["b"]] : never[]
>...obj?.a["b"] : any
>obj?.a["b"] : any
>obj?.a : any
>obj : any
>a : any
>"b" : "b"
>[] : never[]
@@ -0,0 +1,37 @@
//// [elementAccessChain.ts]
declare const o1: undefined | { b: string };
o1?.["b"];
declare const o2: undefined | { b: { c: string } };
o2?.["b"].c;
o2?.b["c"];
declare const o3: { b: undefined | { c: string } };
o3["b"]?.c;
o3.b?.["c"];
declare const o4: { b?: { c: { d?: { e: string } } } };
o4.b?.["c"].d?.e;
o4.b?.["c"].d?.["e"];
declare const o5: { b?(): { c: { d?: { e: string } } } };
o5.b?.()["c"].d?.e;
o5.b?.()["c"].d?.["e"];
o5["b"]?.()["c"].d?.e;
o5["b"]?.()["c"].d?.["e"];
//// [elementAccessChain.js]
"use strict";
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
(_a = o1) === null || _a === void 0 ? void 0 : _a["b"];
(_b = o2) === null || _b === void 0 ? void 0 : _b["b"].c;
(_c = o2) === null || _c === void 0 ? void 0 : _c.b["c"];
(_d = o3["b"]) === null || _d === void 0 ? void 0 : _d.c;
(_e = o3.b) === null || _e === void 0 ? void 0 : _e["c"];
(_g = (_f = o4.b) === null || _f === void 0 ? void 0 : _f["c"].d) === null || _g === void 0 ? void 0 : _g.e;
(_j = (_h = o4.b) === null || _h === void 0 ? void 0 : _h["c"].d) === null || _j === void 0 ? void 0 : _j["e"];
(_m = (_l = (_k = o5).b) === null || _l === void 0 ? void 0 : _l.call(_k)["c"].d) === null || _m === void 0 ? void 0 : _m.e;
(_q = (_p = (_o = o5).b) === null || _p === void 0 ? void 0 : _p.call(_o)["c"].d) === null || _q === void 0 ? void 0 : _q["e"];
(_t = (_s = (_r = o5)["b"]) === null || _s === void 0 ? void 0 : _s.call(_r)["c"].d) === null || _t === void 0 ? void 0 : _t.e;
(_w = (_v = (_u = o5)["b"]) === null || _v === void 0 ? void 0 : _v.call(_u)["c"].d) === null || _w === void 0 ? void 0 : _w["e"];
@@ -0,0 +1,99 @@
=== tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.ts ===
declare const o1: undefined | { b: string };
>o1 : Symbol(o1, Decl(elementAccessChain.ts, 0, 13))
>b : Symbol(b, Decl(elementAccessChain.ts, 0, 31))
o1?.["b"];
>o1 : Symbol(o1, Decl(elementAccessChain.ts, 0, 13))
declare const o2: undefined | { b: { c: string } };
>o2 : Symbol(o2, Decl(elementAccessChain.ts, 3, 13))
>b : Symbol(b, Decl(elementAccessChain.ts, 3, 31))
>c : Symbol(c, Decl(elementAccessChain.ts, 3, 36))
o2?.["b"].c;
>o2?.["b"].c : Symbol(c, Decl(elementAccessChain.ts, 3, 36))
>o2 : Symbol(o2, Decl(elementAccessChain.ts, 3, 13))
>c : Symbol(c, Decl(elementAccessChain.ts, 3, 36))
o2?.b["c"];
>o2?.b : Symbol(b, Decl(elementAccessChain.ts, 3, 31))
>o2 : Symbol(o2, Decl(elementAccessChain.ts, 3, 13))
>b : Symbol(b, Decl(elementAccessChain.ts, 3, 31))
declare const o3: { b: undefined | { c: string } };
>o3 : Symbol(o3, Decl(elementAccessChain.ts, 7, 13))
>b : Symbol(b, Decl(elementAccessChain.ts, 7, 19))
>c : Symbol(c, Decl(elementAccessChain.ts, 7, 36))
o3["b"]?.c;
>o3["b"]?.c : Symbol(c, Decl(elementAccessChain.ts, 7, 36))
>o3 : Symbol(o3, Decl(elementAccessChain.ts, 7, 13))
>"b" : Symbol(b, Decl(elementAccessChain.ts, 7, 19))
>c : Symbol(c, Decl(elementAccessChain.ts, 7, 36))
o3.b?.["c"];
>o3.b : Symbol(b, Decl(elementAccessChain.ts, 7, 19))
>o3 : Symbol(o3, Decl(elementAccessChain.ts, 7, 13))
>b : Symbol(b, Decl(elementAccessChain.ts, 7, 19))
declare const o4: { b?: { c: { d?: { e: string } } } };
>o4 : Symbol(o4, Decl(elementAccessChain.ts, 11, 13))
>b : Symbol(b, Decl(elementAccessChain.ts, 11, 19))
>c : Symbol(c, Decl(elementAccessChain.ts, 11, 25))
>d : Symbol(d, Decl(elementAccessChain.ts, 11, 30))
>e : Symbol(e, Decl(elementAccessChain.ts, 11, 36))
o4.b?.["c"].d?.e;
>o4.b?.["c"].d?.e : Symbol(e, Decl(elementAccessChain.ts, 11, 36))
>o4.b?.["c"].d : Symbol(d, Decl(elementAccessChain.ts, 11, 30))
>o4.b : Symbol(b, Decl(elementAccessChain.ts, 11, 19))
>o4 : Symbol(o4, Decl(elementAccessChain.ts, 11, 13))
>b : Symbol(b, Decl(elementAccessChain.ts, 11, 19))
>d : Symbol(d, Decl(elementAccessChain.ts, 11, 30))
>e : Symbol(e, Decl(elementAccessChain.ts, 11, 36))
o4.b?.["c"].d?.["e"];
>o4.b?.["c"].d : Symbol(d, Decl(elementAccessChain.ts, 11, 30))
>o4.b : Symbol(b, Decl(elementAccessChain.ts, 11, 19))
>o4 : Symbol(o4, Decl(elementAccessChain.ts, 11, 13))
>b : Symbol(b, Decl(elementAccessChain.ts, 11, 19))
>d : Symbol(d, Decl(elementAccessChain.ts, 11, 30))
declare const o5: { b?(): { c: { d?: { e: string } } } };
>o5 : Symbol(o5, Decl(elementAccessChain.ts, 15, 13))
>b : Symbol(b, Decl(elementAccessChain.ts, 15, 19))
>c : Symbol(c, Decl(elementAccessChain.ts, 15, 27))
>d : Symbol(d, Decl(elementAccessChain.ts, 15, 32))
>e : Symbol(e, Decl(elementAccessChain.ts, 15, 38))
o5.b?.()["c"].d?.e;
>o5.b?.()["c"].d?.e : Symbol(e, Decl(elementAccessChain.ts, 15, 38))
>o5.b?.()["c"].d : Symbol(d, Decl(elementAccessChain.ts, 15, 32))
>o5.b : Symbol(b, Decl(elementAccessChain.ts, 15, 19))
>o5 : Symbol(o5, Decl(elementAccessChain.ts, 15, 13))
>b : Symbol(b, Decl(elementAccessChain.ts, 15, 19))
>d : Symbol(d, Decl(elementAccessChain.ts, 15, 32))
>e : Symbol(e, Decl(elementAccessChain.ts, 15, 38))
o5.b?.()["c"].d?.["e"];
>o5.b?.()["c"].d : Symbol(d, Decl(elementAccessChain.ts, 15, 32))
>o5.b : Symbol(b, Decl(elementAccessChain.ts, 15, 19))
>o5 : Symbol(o5, Decl(elementAccessChain.ts, 15, 13))
>b : Symbol(b, Decl(elementAccessChain.ts, 15, 19))
>d : Symbol(d, Decl(elementAccessChain.ts, 15, 32))
o5["b"]?.()["c"].d?.e;
>o5["b"]?.()["c"].d?.e : Symbol(e, Decl(elementAccessChain.ts, 15, 38))
>o5["b"]?.()["c"].d : Symbol(d, Decl(elementAccessChain.ts, 15, 32))
>o5 : Symbol(o5, Decl(elementAccessChain.ts, 15, 13))
>"b" : Symbol(b, Decl(elementAccessChain.ts, 15, 19))
>d : Symbol(d, Decl(elementAccessChain.ts, 15, 32))
>e : Symbol(e, Decl(elementAccessChain.ts, 15, 38))
o5["b"]?.()["c"].d?.["e"];
>o5["b"]?.()["c"].d : Symbol(d, Decl(elementAccessChain.ts, 15, 32))
>o5 : Symbol(o5, Decl(elementAccessChain.ts, 15, 13))
>"b" : Symbol(b, Decl(elementAccessChain.ts, 15, 19))
>d : Symbol(d, Decl(elementAccessChain.ts, 15, 32))
@@ -0,0 +1,132 @@
=== tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.ts ===
declare const o1: undefined | { b: string };
>o1 : { b: string; } | undefined
>b : string
o1?.["b"];
>o1?.["b"] : string | undefined
>o1 : { b: string; } | undefined
>"b" : "b"
declare const o2: undefined | { b: { c: string } };
>o2 : { b: { c: string; }; } | undefined
>b : { c: string; }
>c : string
o2?.["b"].c;
>o2?.["b"].c : string | undefined
>o2?.["b"] : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>"b" : "b"
>c : string | undefined
o2?.b["c"];
>o2?.b["c"] : string | undefined
>o2?.b : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>b : { c: string; } | undefined
>"c" : "c"
declare const o3: { b: undefined | { c: string } };
>o3 : { b: { c: string; } | undefined; }
>b : { c: string; } | undefined
>c : string
o3["b"]?.c;
>o3["b"]?.c : string | undefined
>o3["b"] : { c: string; } | undefined
>o3 : { b: { c: string; } | undefined; }
>"b" : "b"
>c : string | undefined
o3.b?.["c"];
>o3.b?.["c"] : string | undefined
>o3.b : { c: string; } | undefined
>o3 : { b: { c: string; } | undefined; }
>b : { c: string; } | undefined
>"c" : "c"
declare const o4: { b?: { c: { d?: { e: string } } } };
>o4 : { b?: { c: { d?: { e: string; } | undefined; }; } | undefined; }
>b : { c: { d?: { e: string; } | undefined; }; } | undefined
>c : { d?: { e: string; } | undefined; }
>d : { e: string; } | undefined
>e : string
o4.b?.["c"].d?.e;
>o4.b?.["c"].d?.e : string | undefined
>o4.b?.["c"].d : { e: string; } | undefined
>o4.b?.["c"] : { d?: { e: string; } | undefined; } | undefined
>o4.b : { c: { d?: { e: string; } | undefined; }; } | undefined
>o4 : { b?: { c: { d?: { e: string; } | undefined; }; } | undefined; }
>b : { c: { d?: { e: string; } | undefined; }; } | undefined
>"c" : "c"
>d : { e: string; } | undefined
>e : string | undefined
o4.b?.["c"].d?.["e"];
>o4.b?.["c"].d?.["e"] : string | undefined
>o4.b?.["c"].d : { e: string; } | undefined
>o4.b?.["c"] : { d?: { e: string; } | undefined; } | undefined
>o4.b : { c: { d?: { e: string; } | undefined; }; } | undefined
>o4 : { b?: { c: { d?: { e: string; } | undefined; }; } | undefined; }
>b : { c: { d?: { e: string; } | undefined; }; } | undefined
>"c" : "c"
>d : { e: string; } | undefined
>"e" : "e"
declare const o5: { b?(): { c: { d?: { e: string } } } };
>o5 : { b?(): { c: { d?: { e: string; } | undefined; }; }; }
>b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>c : { d?: { e: string; } | undefined; }
>d : { e: string; } | undefined
>e : string
o5.b?.()["c"].d?.e;
>o5.b?.()["c"].d?.e : string | undefined
>o5.b?.()["c"].d : { e: string; } | undefined
>o5.b?.()["c"] : { d?: { e: string; } | undefined; } | undefined
>o5.b?.() : { c: { d?: { e: string; } | undefined; }; } | undefined
>o5.b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>o5 : { b?(): { c: { d?: { e: string; } | undefined; }; }; }
>b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>"c" : "c"
>d : { e: string; } | undefined
>e : string | undefined
o5.b?.()["c"].d?.["e"];
>o5.b?.()["c"].d?.["e"] : string | undefined
>o5.b?.()["c"].d : { e: string; } | undefined
>o5.b?.()["c"] : { d?: { e: string; } | undefined; } | undefined
>o5.b?.() : { c: { d?: { e: string; } | undefined; }; } | undefined
>o5.b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>o5 : { b?(): { c: { d?: { e: string; } | undefined; }; }; }
>b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>"c" : "c"
>d : { e: string; } | undefined
>"e" : "e"
o5["b"]?.()["c"].d?.e;
>o5["b"]?.()["c"].d?.e : string | undefined
>o5["b"]?.()["c"].d : { e: string; } | undefined
>o5["b"]?.()["c"] : { d?: { e: string; } | undefined; } | undefined
>o5["b"]?.() : { c: { d?: { e: string; } | undefined; }; } | undefined
>o5["b"] : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>o5 : { b?(): { c: { d?: { e: string; } | undefined; }; }; }
>"b" : "b"
>"c" : "c"
>d : { e: string; } | undefined
>e : string | undefined
o5["b"]?.()["c"].d?.["e"];
>o5["b"]?.()["c"].d?.["e"] : string | undefined
>o5["b"]?.()["c"].d : { e: string; } | undefined
>o5["b"]?.()["c"] : { d?: { e: string; } | undefined; } | undefined
>o5["b"]?.() : { c: { d?: { e: string; } | undefined; }; } | undefined
>o5["b"] : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>o5 : { b?(): { c: { d?: { e: string; } | undefined; }; }; }
>"b" : "b"
>"c" : "c"
>d : { e: string; } | undefined
>"e" : "e"
@@ -0,0 +1,16 @@
//// [propertyAccessChain.2.ts]
declare const o1: undefined | { b: string };
o1?.b;
declare const o2: undefined | { b: { c: string } };
o2?.b.c;
declare const o3: { b: undefined | { c: string } };
o3.b?.c;
//// [propertyAccessChain.2.js]
var _a, _b, _c;
(_a = o1) === null || _a === void 0 ? void 0 : _a.b;
(_b = o2) === null || _b === void 0 ? void 0 : _b.b.c;
(_c = o3.b) === null || _c === void 0 ? void 0 : _c.c;
@@ -0,0 +1,34 @@
=== tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.2.ts ===
declare const o1: undefined | { b: string };
>o1 : Symbol(o1, Decl(propertyAccessChain.2.ts, 0, 13))
>b : Symbol(b, Decl(propertyAccessChain.2.ts, 0, 31))
o1?.b;
>o1?.b : Symbol(b, Decl(propertyAccessChain.2.ts, 0, 31))
>o1 : Symbol(o1, Decl(propertyAccessChain.2.ts, 0, 13))
>b : Symbol(b, Decl(propertyAccessChain.2.ts, 0, 31))
declare const o2: undefined | { b: { c: string } };
>o2 : Symbol(o2, Decl(propertyAccessChain.2.ts, 3, 13))
>b : Symbol(b, Decl(propertyAccessChain.2.ts, 3, 31))
>c : Symbol(c, Decl(propertyAccessChain.2.ts, 3, 36))
o2?.b.c;
>o2?.b.c : Symbol(c, Decl(propertyAccessChain.2.ts, 3, 36))
>o2?.b : Symbol(b, Decl(propertyAccessChain.2.ts, 3, 31))
>o2 : Symbol(o2, Decl(propertyAccessChain.2.ts, 3, 13))
>b : Symbol(b, Decl(propertyAccessChain.2.ts, 3, 31))
>c : Symbol(c, Decl(propertyAccessChain.2.ts, 3, 36))
declare const o3: { b: undefined | { c: string } };
>o3 : Symbol(o3, Decl(propertyAccessChain.2.ts, 6, 13))
>b : Symbol(b, Decl(propertyAccessChain.2.ts, 6, 19))
>c : Symbol(c, Decl(propertyAccessChain.2.ts, 6, 36))
o3.b?.c;
>o3.b?.c : Symbol(c, Decl(propertyAccessChain.2.ts, 6, 36))
>o3.b : Symbol(b, Decl(propertyAccessChain.2.ts, 6, 19))
>o3 : Symbol(o3, Decl(propertyAccessChain.2.ts, 6, 13))
>b : Symbol(b, Decl(propertyAccessChain.2.ts, 6, 19))
>c : Symbol(c, Decl(propertyAccessChain.2.ts, 6, 36))
@@ -0,0 +1,34 @@
=== tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.2.ts ===
declare const o1: undefined | { b: string };
>o1 : { b: string; }
>b : string
o1?.b;
>o1?.b : string
>o1 : { b: string; }
>b : string
declare const o2: undefined | { b: { c: string } };
>o2 : { b: { c: string; }; }
>b : { c: string; }
>c : string
o2?.b.c;
>o2?.b.c : string
>o2?.b : { c: string; }
>o2 : { b: { c: string; }; }
>b : { c: string; }
>c : string
declare const o3: { b: undefined | { c: string } };
>o3 : { b: { c: string; }; }
>b : { c: string; }
>c : string
o3.b?.c;
>o3.b?.c : string
>o3.b : { c: string; }
>o3 : { b: { c: string; }; }
>b : { c: string; }
>c : string
@@ -0,0 +1,98 @@
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(3,1): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(4,1): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(5,1): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(6,1): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(8,3): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(9,3): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(10,3): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(11,3): error TS2777: The operand of an increment or decrement operator may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(13,1): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(14,1): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(15,1): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(16,1): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(18,6): error TS2780: The left-hand side of a 'for...in' statement may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(19,6): error TS2780: The left-hand side of a 'for...in' statement may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(20,6): error TS2781: The left-hand side of a 'for...of' statement may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(21,6): error TS2781: The left-hand side of a 'for...of' statement may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(23,7): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(24,7): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(25,7): error TS2778: The target of an object rest assignment may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(26,7): error TS2778: The target of an object rest assignment may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(27,5): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts(28,5): error TS2779: The left-hand side of an assignment expression may not be an optional property access.
==== tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts (22 errors) ====
declare const obj: any;
obj?.a++;
~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
obj?.a.b++;
~~~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
obj?.a--;
~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
obj?.a.b--;
~~~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
++obj?.a;
~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
++obj?.a.b;
~~~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
--obj?.a;
~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
--obj?.a.b;
~~~~~~~~
!!! error TS2777: The operand of an increment or decrement operator may not be an optional property access.
obj?.a = 1;
~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
obj?.a.b = 1;
~~~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
obj?.a += 1;
~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
obj?.a.b += 1;
~~~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
for (obj?.a in {});
~~~~~~
!!! error TS2780: The left-hand side of a 'for...in' statement may not be an optional property access.
for (obj?.a.b in {});
~~~~~~~~
!!! error TS2780: The left-hand side of a 'for...in' statement may not be an optional property access.
for (obj?.a of []);
~~~~~~
!!! error TS2781: The left-hand side of a 'for...of' statement may not be an optional property access.
for (obj?.a.b of []);
~~~~~~~~
!!! error TS2781: The left-hand side of a 'for...of' statement may not be an optional property access.
({ a: obj?.a } = { a: 1 });
~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
({ a: obj?.a.b } = { a: 1 });
~~~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
({ ...obj?.a } = { a: 1 });
~~~~~~
!!! error TS2778: The target of an object rest assignment may not be an optional property access.
({ ...obj?.a.b } = { a: 1 });
~~~~~~~~
!!! error TS2778: The target of an object rest assignment may not be an optional property access.
[...obj?.a] = [];
~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
[...obj?.a.b] = [];
~~~~~~~~
!!! error TS2779: The left-hand side of an assignment expression may not be an optional property access.
@@ -0,0 +1,75 @@
//// [propertyAccessChain.3.ts]
declare const obj: any;
obj?.a++;
obj?.a.b++;
obj?.a--;
obj?.a.b--;
++obj?.a;
++obj?.a.b;
--obj?.a;
--obj?.a.b;
obj?.a = 1;
obj?.a.b = 1;
obj?.a += 1;
obj?.a.b += 1;
for (obj?.a in {});
for (obj?.a.b in {});
for (obj?.a of []);
for (obj?.a.b of []);
({ a: obj?.a } = { a: 1 });
({ a: obj?.a.b } = { a: 1 });
({ ...obj?.a } = { a: 1 });
({ ...obj?.a.b } = { a: 1 });
[...obj?.a] = [];
[...obj?.a.b] = [];
//// [propertyAccessChain.3.js]
"use strict";
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
((_a = obj) === null || _a === void 0 ? void 0 : _a.a)++;
((_b = obj) === null || _b === void 0 ? void 0 : _b.a.b)++;
((_c = obj) === null || _c === void 0 ? void 0 : _c.a)--;
((_d = obj) === null || _d === void 0 ? void 0 : _d.a.b)--;
++((_e = obj) === null || _e === void 0 ? void 0 : _e.a);
++((_f = obj) === null || _f === void 0 ? void 0 : _f.a.b);
--((_g = obj) === null || _g === void 0 ? void 0 : _g.a);
--((_h = obj) === null || _h === void 0 ? void 0 : _h.a.b);
(_j = obj) === null || _j === void 0 ? void 0 : _j.a = 1;
(_k = obj) === null || _k === void 0 ? void 0 : _k.a.b = 1;
(_l = obj) === null || _l === void 0 ? void 0 : _l.a += 1;
(_m = obj) === null || _m === void 0 ? void 0 : _m.a.b += 1;
for ((_o = obj) === null || _o === void 0 ? void 0 : _o.a in {})
;
for ((_p = obj) === null || _p === void 0 ? void 0 : _p.a.b in {})
;
for (var _i = 0, _y = []; _i < _y.length; _i++) {
(_q = obj) === null || _q === void 0 ? void 0 : _q.a = _y[_i];
;
}
for (var _z = 0, _0 = []; _z < _0.length; _z++) {
(_r = obj) === null || _r === void 0 ? void 0 : _r.a.b = _0[_z];
;
}
((_s = obj) === null || _s === void 0 ? void 0 : _s.a = { a: 1 }.a);
((_t = obj) === null || _t === void 0 ? void 0 : _t.a.b = { a: 1 }.a);
((_u = obj) === null || _u === void 0 ? void 0 : _u.a = __rest({ a: 1 }, []));
((_v = obj) === null || _v === void 0 ? void 0 : _v.a.b = __rest({ a: 1 }, []));
(_w = obj) === null || _w === void 0 ? void 0 : _w.a = [].slice(0);
(_x = obj) === null || _x === void 0 ? void 0 : _x.a.b = [].slice(0);
@@ -0,0 +1,76 @@
=== tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts ===
declare const obj: any;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
obj?.a++;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
obj?.a.b++;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
obj?.a--;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
obj?.a.b--;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
++obj?.a;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
++obj?.a.b;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
--obj?.a;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
--obj?.a.b;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
obj?.a = 1;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
obj?.a.b = 1;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
obj?.a += 1;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
obj?.a.b += 1;
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
for (obj?.a in {});
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
for (obj?.a.b in {});
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
for (obj?.a of []);
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
for (obj?.a.b of []);
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
({ a: obj?.a } = { a: 1 });
>a : Symbol(a, Decl(propertyAccessChain.3.ts, 22, 2))
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
>a : Symbol(a, Decl(propertyAccessChain.3.ts, 22, 18))
({ a: obj?.a.b } = { a: 1 });
>a : Symbol(a, Decl(propertyAccessChain.3.ts, 23, 2))
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
>a : Symbol(a, Decl(propertyAccessChain.3.ts, 23, 20))
({ ...obj?.a } = { a: 1 });
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
>a : Symbol(a, Decl(propertyAccessChain.3.ts, 24, 18))
({ ...obj?.a.b } = { a: 1 });
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
>a : Symbol(a, Decl(propertyAccessChain.3.ts, 25, 20))
[...obj?.a] = [];
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
[...obj?.a.b] = [];
>obj : Symbol(obj, Decl(propertyAccessChain.3.ts, 0, 13))
@@ -0,0 +1,190 @@
=== tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.3.ts ===
declare const obj: any;
>obj : any
obj?.a++;
>obj?.a++ : number
>obj?.a : any
>obj : any
>a : any
obj?.a.b++;
>obj?.a.b++ : number
>obj?.a.b : any
>obj?.a : any
>obj : any
>a : any
>b : any
obj?.a--;
>obj?.a-- : number
>obj?.a : any
>obj : any
>a : any
obj?.a.b--;
>obj?.a.b-- : number
>obj?.a.b : any
>obj?.a : any
>obj : any
>a : any
>b : any
++obj?.a;
>++obj?.a : number
>obj?.a : any
>obj : any
>a : any
++obj?.a.b;
>++obj?.a.b : number
>obj?.a.b : any
>obj?.a : any
>obj : any
>a : any
>b : any
--obj?.a;
>--obj?.a : number
>obj?.a : any
>obj : any
>a : any
--obj?.a.b;
>--obj?.a.b : number
>obj?.a.b : any
>obj?.a : any
>obj : any
>a : any
>b : any
obj?.a = 1;
>obj?.a = 1 : 1
>obj?.a : any
>obj : any
>a : any
>1 : 1
obj?.a.b = 1;
>obj?.a.b = 1 : 1
>obj?.a.b : any
>obj?.a : any
>obj : any
>a : any
>b : any
>1 : 1
obj?.a += 1;
>obj?.a += 1 : any
>obj?.a : any
>obj : any
>a : any
>1 : 1
obj?.a.b += 1;
>obj?.a.b += 1 : any
>obj?.a.b : any
>obj?.a : any
>obj : any
>a : any
>b : any
>1 : 1
for (obj?.a in {});
>obj?.a : any
>obj : any
>a : any
>{} : {}
for (obj?.a.b in {});
>obj?.a.b : any
>obj?.a : any
>obj : any
>a : any
>b : any
>{} : {}
for (obj?.a of []);
>obj?.a : any
>obj : any
>a : any
>[] : never[]
for (obj?.a.b of []);
>obj?.a.b : any
>obj?.a : any
>obj : any
>a : any
>b : any
>[] : never[]
({ a: obj?.a } = { a: 1 });
>({ a: obj?.a } = { a: 1 }) : { a: number; }
>{ a: obj?.a } = { a: 1 } : { a: number; }
>{ a: obj?.a } : { a: any; }
>a : any
>obj?.a : any
>obj : any
>a : any
>{ a: 1 } : { a: number; }
>a : number
>1 : 1
({ a: obj?.a.b } = { a: 1 });
>({ a: obj?.a.b } = { a: 1 }) : { a: number; }
>{ a: obj?.a.b } = { a: 1 } : { a: number; }
>{ a: obj?.a.b } : { a: any; }
>a : any
>obj?.a.b : any
>obj?.a : any
>obj : any
>a : any
>b : any
>{ a: 1 } : { a: number; }
>a : number
>1 : 1
({ ...obj?.a } = { a: 1 });
>({ ...obj?.a } = { a: 1 }) : { a: number; }
>{ ...obj?.a } = { a: 1 } : { a: number; }
>{ ...obj?.a } : any
>obj?.a : any
>obj : any
>a : any
>{ a: 1 } : { a: number; }
>a : number
>1 : 1
({ ...obj?.a.b } = { a: 1 });
>({ ...obj?.a.b } = { a: 1 }) : { a: number; }
>{ ...obj?.a.b } = { a: 1 } : { a: number; }
>{ ...obj?.a.b } : any
>obj?.a.b : any
>obj?.a : any
>obj : any
>a : any
>b : any
>{ a: 1 } : { a: number; }
>a : number
>1 : 1
[...obj?.a] = [];
>[...obj?.a] = [] : never[]
>[...obj?.a] : never[]
>...obj?.a : any
>obj?.a : any
>obj : any
>a : any
>[] : never[]
[...obj?.a.b] = [];
>[...obj?.a.b] = [] : never[]
>[...obj?.a.b] : never[]
>...obj?.a.b : any
>obj?.a.b : any
>obj?.a : any
>obj : any
>a : any
>b : any
>[] : never[]
@@ -0,0 +1,25 @@
//// [propertyAccessChain.ts]
declare const o1: undefined | { b: string };
o1?.b;
declare const o2: undefined | { b: { c: string } };
o2?.b.c;
declare const o3: { b: undefined | { c: string } };
o3.b?.c;
declare const o4: { b?: { c: { d?: { e: string } } } };
o4.b?.c.d?.e;
declare const o5: { b?(): { c: { d?: { e: string } } } };
o5.b?.().c.d?.e;
//// [propertyAccessChain.js]
"use strict";
var _a, _b, _c, _d, _e, _f, _g, _h;
(_a = o1) === null || _a === void 0 ? void 0 : _a.b;
(_b = o2) === null || _b === void 0 ? void 0 : _b.b.c;
(_c = o3.b) === null || _c === void 0 ? void 0 : _c.c;
(_e = (_d = o4.b) === null || _d === void 0 ? void 0 : _d.c.d) === null || _e === void 0 ? void 0 : _e.e;
(_h = (_g = (_f = o5).b) === null || _g === void 0 ? void 0 : _g.call(_f).c.d) === null || _h === void 0 ? void 0 : _h.e;
@@ -0,0 +1,70 @@
=== tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.ts ===
declare const o1: undefined | { b: string };
>o1 : Symbol(o1, Decl(propertyAccessChain.ts, 0, 13))
>b : Symbol(b, Decl(propertyAccessChain.ts, 0, 31))
o1?.b;
>o1?.b : Symbol(b, Decl(propertyAccessChain.ts, 0, 31))
>o1 : Symbol(o1, Decl(propertyAccessChain.ts, 0, 13))
>b : Symbol(b, Decl(propertyAccessChain.ts, 0, 31))
declare const o2: undefined | { b: { c: string } };
>o2 : Symbol(o2, Decl(propertyAccessChain.ts, 3, 13))
>b : Symbol(b, Decl(propertyAccessChain.ts, 3, 31))
>c : Symbol(c, Decl(propertyAccessChain.ts, 3, 36))
o2?.b.c;
>o2?.b.c : Symbol(c, Decl(propertyAccessChain.ts, 3, 36))
>o2?.b : Symbol(b, Decl(propertyAccessChain.ts, 3, 31))
>o2 : Symbol(o2, Decl(propertyAccessChain.ts, 3, 13))
>b : Symbol(b, Decl(propertyAccessChain.ts, 3, 31))
>c : Symbol(c, Decl(propertyAccessChain.ts, 3, 36))
declare const o3: { b: undefined | { c: string } };
>o3 : Symbol(o3, Decl(propertyAccessChain.ts, 6, 13))
>b : Symbol(b, Decl(propertyAccessChain.ts, 6, 19))
>c : Symbol(c, Decl(propertyAccessChain.ts, 6, 36))
o3.b?.c;
>o3.b?.c : Symbol(c, Decl(propertyAccessChain.ts, 6, 36))
>o3.b : Symbol(b, Decl(propertyAccessChain.ts, 6, 19))
>o3 : Symbol(o3, Decl(propertyAccessChain.ts, 6, 13))
>b : Symbol(b, Decl(propertyAccessChain.ts, 6, 19))
>c : Symbol(c, Decl(propertyAccessChain.ts, 6, 36))
declare const o4: { b?: { c: { d?: { e: string } } } };
>o4 : Symbol(o4, Decl(propertyAccessChain.ts, 9, 13))
>b : Symbol(b, Decl(propertyAccessChain.ts, 9, 19))
>c : Symbol(c, Decl(propertyAccessChain.ts, 9, 25))
>d : Symbol(d, Decl(propertyAccessChain.ts, 9, 30))
>e : Symbol(e, Decl(propertyAccessChain.ts, 9, 36))
o4.b?.c.d?.e;
>o4.b?.c.d?.e : Symbol(e, Decl(propertyAccessChain.ts, 9, 36))
>o4.b?.c.d : Symbol(d, Decl(propertyAccessChain.ts, 9, 30))
>o4.b?.c : Symbol(c, Decl(propertyAccessChain.ts, 9, 25))
>o4.b : Symbol(b, Decl(propertyAccessChain.ts, 9, 19))
>o4 : Symbol(o4, Decl(propertyAccessChain.ts, 9, 13))
>b : Symbol(b, Decl(propertyAccessChain.ts, 9, 19))
>c : Symbol(c, Decl(propertyAccessChain.ts, 9, 25))
>d : Symbol(d, Decl(propertyAccessChain.ts, 9, 30))
>e : Symbol(e, Decl(propertyAccessChain.ts, 9, 36))
declare const o5: { b?(): { c: { d?: { e: string } } } };
>o5 : Symbol(o5, Decl(propertyAccessChain.ts, 12, 13))
>b : Symbol(b, Decl(propertyAccessChain.ts, 12, 19))
>c : Symbol(c, Decl(propertyAccessChain.ts, 12, 27))
>d : Symbol(d, Decl(propertyAccessChain.ts, 12, 32))
>e : Symbol(e, Decl(propertyAccessChain.ts, 12, 38))
o5.b?.().c.d?.e;
>o5.b?.().c.d?.e : Symbol(e, Decl(propertyAccessChain.ts, 12, 38))
>o5.b?.().c.d : Symbol(d, Decl(propertyAccessChain.ts, 12, 32))
>o5.b?.().c : Symbol(c, Decl(propertyAccessChain.ts, 12, 27))
>o5.b : Symbol(b, Decl(propertyAccessChain.ts, 12, 19))
>o5 : Symbol(o5, Decl(propertyAccessChain.ts, 12, 13))
>b : Symbol(b, Decl(propertyAccessChain.ts, 12, 19))
>c : Symbol(c, Decl(propertyAccessChain.ts, 12, 27))
>d : Symbol(d, Decl(propertyAccessChain.ts, 12, 32))
>e : Symbol(e, Decl(propertyAccessChain.ts, 12, 38))
@@ -0,0 +1,71 @@
=== tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.ts ===
declare const o1: undefined | { b: string };
>o1 : { b: string; } | undefined
>b : string
o1?.b;
>o1?.b : string | undefined
>o1 : { b: string; } | undefined
>b : string | undefined
declare const o2: undefined | { b: { c: string } };
>o2 : { b: { c: string; }; } | undefined
>b : { c: string; }
>c : string
o2?.b.c;
>o2?.b.c : string | undefined
>o2?.b : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>b : { c: string; } | undefined
>c : string | undefined
declare const o3: { b: undefined | { c: string } };
>o3 : { b: { c: string; } | undefined; }
>b : { c: string; } | undefined
>c : string
o3.b?.c;
>o3.b?.c : string | undefined
>o3.b : { c: string; } | undefined
>o3 : { b: { c: string; } | undefined; }
>b : { c: string; } | undefined
>c : string | undefined
declare const o4: { b?: { c: { d?: { e: string } } } };
>o4 : { b?: { c: { d?: { e: string; } | undefined; }; } | undefined; }
>b : { c: { d?: { e: string; } | undefined; }; } | undefined
>c : { d?: { e: string; } | undefined; }
>d : { e: string; } | undefined
>e : string
o4.b?.c.d?.e;
>o4.b?.c.d?.e : string | undefined
>o4.b?.c.d : { e: string; } | undefined
>o4.b?.c : { d?: { e: string; } | undefined; } | undefined
>o4.b : { c: { d?: { e: string; } | undefined; }; } | undefined
>o4 : { b?: { c: { d?: { e: string; } | undefined; }; } | undefined; }
>b : { c: { d?: { e: string; } | undefined; }; } | undefined
>c : { d?: { e: string; } | undefined; } | undefined
>d : { e: string; } | undefined
>e : string | undefined
declare const o5: { b?(): { c: { d?: { e: string } } } };
>o5 : { b?(): { c: { d?: { e: string; } | undefined; }; }; }
>b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>c : { d?: { e: string; } | undefined; }
>d : { e: string; } | undefined
>e : string
o5.b?.().c.d?.e;
>o5.b?.().c.d?.e : string | undefined
>o5.b?.().c.d : { e: string; } | undefined
>o5.b?.().c : { d?: { e: string; } | undefined; } | undefined
>o5.b?.() : { c: { d?: { e: string; } | undefined; }; } | undefined
>o5.b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>o5 : { b?(): { c: { d?: { e: string; } | undefined; }; }; }
>b : (() => { c: { d?: { e: string; } | undefined; }; }) | undefined
>c : { d?: { e: string; } | undefined; } | undefined
>d : { e: string; } | undefined
>e : string | undefined
@@ -0,0 +1,13 @@
tests/cases/conformance/expressions/optionalChaining/taggedTemplateChain/taggedTemplateChain.ts(2,4): error TS1358: Tagged template expressions are not permitted in an optional chain.
tests/cases/conformance/expressions/optionalChaining/taggedTemplateChain/taggedTemplateChain.ts(4,4): error TS1358: Tagged template expressions are not permitted in an optional chain.
==== tests/cases/conformance/expressions/optionalChaining/taggedTemplateChain/taggedTemplateChain.ts (2 errors) ====
declare let a: any;
a?.`b`;
~~~
!!! error TS1358: Tagged template expressions are not permitted in an optional chain.
a?.`b${1}c`;
~~~~~~~~
!!! error TS1358: Tagged template expressions are not permitted in an optional chain.
@@ -0,0 +1,13 @@
//// [taggedTemplateChain.ts]
declare let a: any;
a?.`b`;
a?.`b${1}c`;
//// [taggedTemplateChain.js]
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
return cooked;
};
a(__makeTemplateObject(["b"], ["b"]));
a(__makeTemplateObject(["b", "c"], ["b", "c"]), 1);
@@ -0,0 +1,10 @@
=== tests/cases/conformance/expressions/optionalChaining/taggedTemplateChain/taggedTemplateChain.ts ===
declare let a: any;
>a : Symbol(a, Decl(taggedTemplateChain.ts, 0, 11))
a?.`b`;
>a : Symbol(a, Decl(taggedTemplateChain.ts, 0, 11))
a?.`b${1}c`;
>a : Symbol(a, Decl(taggedTemplateChain.ts, 0, 11))
@@ -0,0 +1,15 @@
=== tests/cases/conformance/expressions/optionalChaining/taggedTemplateChain/taggedTemplateChain.ts ===
declare let a: any;
>a : any
a?.`b`;
>a?.`b` : any
>a : any
>`b` : "b"
a?.`b${1}c`;
>a?.`b${1}c` : any
>a : any
>`b${1}c` : string
>1 : 1
@@ -0,0 +1,163 @@
// @strict: true
// @allowUnreachableCode: false
// assignments in shortcutting chain
declare const o: undefined | {
[key: string]: any;
[key: number]: any;
(...args: any[]): any;
};
let a: number;
o?.[a = 1];
a.toString();
let b: number;
o?.x[b = 1];
b.toString();
let c: number;
o?.(c = 1)
c.toString();
let d: number;
o?.x(d = 1);
d.toString();
// type predicates
declare const f: undefined | ((x: any) => x is number);
declare const x: string | number;
if (f?.(x)) {
x; // number
f; // (x: any) => x is number
f(x);
}
else {
x;
f;
f(x);
}
x;
f;
f(x);
declare const o2: { f(x: any): x is number; } | undefined;
if (o2?.f(x)) {
x; // number
o2.f; // (x: any) => x is number
o2?.f;
o2?.f(x);
}
else {
x;
o2;
o2?.f;
o2.f;
}
x;
o2;
o2?.f;
o2.f;
declare const o3: { x: 1, y: string } | { x: 2, y: number } | undefined;
if (o3?.x === 1) {
o3; // TODO: should be `{ x: y, y: string }`
o3.x; // TODO: should not be an error.
o3?.x;
}
else {
o3;
o3?.x;
o3.x;
}
o3;
o3?.x;
o3.x;
declare const o4: { x?: { y: boolean } };
if (o4.x?.y) {
o4.x; // { y: boolean }
o4.x.y; // true
o4.x?.y; // true
}
else {
o4.x;
o4.x?.y;
o4.x.y;
}
o4.x;
o4.x?.y;
o4.x.y;
declare const o5: { x?: { y: { z?: { w: boolean } } } };
if (o5.x?.y.z?.w) {
o5.x;
o5.x.y;
o5.x.y.z;
o5.x.y.z.w; // true
o5.x.y.z?.w; // true
o5.x?.y.z.w; // true
o5.x?.y.z?.w; // true
}
else {
o5.x;
o5.x?.y;
o5.x?.y.z;
o5.x?.y.z?.w;
o5.x.y;
o5.x.y.z.w;
}
o5.x;
o5.x?.y;
o5.x?.y.z;
o5.x?.y.z?.w;
o5.x.y;
o5.x.y.z.w;
interface Base {
f(): this is Derived;
}
interface Derived extends Base {
x: number;
}
declare const o6: Base | undefined;
if (o6?.f()) {
o6; // Derived
o6.f;
}
else {
o6;
o6?.f;
o6.f;
}
o6;
o6?.f;
o6.f;
// asserts
declare const isDefined: <T>(value: T) => asserts value is NonNullable<T>;
declare const isString: (value: unknown) => asserts value is string;
declare const maybeIsString: undefined | ((value: unknown) => asserts value is string);
declare const maybeNever: undefined | (() => never);
function f01(x: unknown) {
if (!!true) {
isString?.(x);
x;
}
if (!!true) {
maybeIsString?.(x);
x;
}
if (!!true) {
isDefined(maybeIsString);
maybeIsString?.(x);
x;
}
if (!!true) {
maybeNever?.();
x;
}
}
@@ -0,0 +1,10 @@
// @strict: false
declare const o1: undefined | (() => number);
o1?.();
declare const o2: undefined | { b: () => number };
o2?.b();
declare const o3: { b: (() => { c: string }) | undefined };
o3.b?.().c;
@@ -0,0 +1,12 @@
// @strict: true
declare function absorb<T>(): T;
declare const a: { m?<T>(obj: {x: T}): T } | undefined;
const n1: number = a?.m?.({x: 12 }); // should be an error (`undefined` is not assignable to `number`)
const n2: number = a?.m?.({x: absorb()}); // likewise
const n3: number | undefined = a?.m?.({x: 12}); // should be ok
const n4: number | undefined = a?.m?.({x: absorb()}); // likewise
// Also a test showing `!` vs `?` for good measure
let t1 = a?.m?.({x: 12});
t1 = a!.m!({x: 12});
@@ -0,0 +1,35 @@
// @strict: true
declare const o1: undefined | ((...args: any[]) => number);
o1?.();
o1?.(1);
o1?.(...[1, 2]);
o1?.(1, ...[2, 3], 4);
declare const o2: undefined | { b: (...args: any[]) => number };
o2?.b();
o2?.b(1);
o2?.b(...[1, 2]);
o2?.b(1, ...[2, 3], 4);
o2?.["b"]();
o2?.["b"](1);
o2?.["b"](...[1, 2]);
o2?.["b"](1, ...[2, 3], 4);
declare const o3: { b: ((...args: any[]) => { c: string }) | undefined };
o3.b?.().c;
o3.b?.(1).c;
o3.b?.(...[1, 2]).c;
o3.b?.(1, ...[2, 3], 4).c;
o3.b?.()["c"];
o3.b?.(1)["c"];
o3.b?.(...[1, 2])["c"];
o3.b?.(1, ...[2, 3], 4)["c"];
o3["b"]?.().c;
o3["b"]?.(1).c;
o3["b"]?.(...[1, 2]).c;
o3["b"]?.(1, ...[2, 3], 4).c;
declare const o4: undefined | (<T>(f: (a: T) => T) => T);
declare function incr(x: number): number;
const v: number | undefined = o4?.(incr);
@@ -0,0 +1,12 @@
// @strict: false
declare const o1: undefined | { b: string };
o1?.["b"];
declare const o2: undefined | { b: { c: string } };
o2?.["b"].c;
o2?.b["c"];
declare const o3: { b: undefined | { c: string } };
o3["b"]?.c;
o3.b?.["c"];
@@ -0,0 +1,30 @@
// @strict: true
declare const obj: any;
obj?.["a"]++;
obj?.a["b"]++;
obj?.["a"]--;
obj?.a["b"]--;
++obj?.["a"];
++obj?.a["b"];
--obj?.["a"];
--obj?.a["b"];
obj?.["a"] = 1;
obj?.a["b"] = 1;
obj?.["a"] += 1;
obj?.a["b"] += 1;
for (obj?.["a"] in {});
for (obj?.a["b"] in {});
for (obj?.["a"] of []);
for (obj?.a["b"] of []);
({ a: obj?.["a"] } = { a: 1 });
({ a: obj?.a["b"] } = { a: 1 });
({ ...obj?.["a"] } = { a: 1 });
({ ...obj?.a["b"] } = { a: 1 });
[...obj?.["a"]] = [];
[...obj?.a["b"]] = [];
@@ -0,0 +1,22 @@
// @strict: true
declare const o1: undefined | { b: string };
o1?.["b"];
declare const o2: undefined | { b: { c: string } };
o2?.["b"].c;
o2?.b["c"];
declare const o3: { b: undefined | { c: string } };
o3["b"]?.c;
o3.b?.["c"];
declare const o4: { b?: { c: { d?: { e: string } } } };
o4.b?.["c"].d?.e;
o4.b?.["c"].d?.["e"];
declare const o5: { b?(): { c: { d?: { e: string } } } };
o5.b?.()["c"].d?.e;
o5.b?.()["c"].d?.["e"];
o5["b"]?.()["c"].d?.e;
o5["b"]?.()["c"].d?.["e"];
@@ -0,0 +1,10 @@
// @strict: false
declare const o1: undefined | { b: string };
o1?.b;
declare const o2: undefined | { b: { c: string } };
o2?.b.c;
declare const o3: { b: undefined | { c: string } };
o3.b?.c;
@@ -0,0 +1,30 @@
// @strict: true
declare const obj: any;
obj?.a++;
obj?.a.b++;
obj?.a--;
obj?.a.b--;
++obj?.a;
++obj?.a.b;
--obj?.a;
--obj?.a.b;
obj?.a = 1;
obj?.a.b = 1;
obj?.a += 1;
obj?.a.b += 1;
for (obj?.a in {});
for (obj?.a.b in {});
for (obj?.a of []);
for (obj?.a.b of []);
({ a: obj?.a } = { a: 1 });
({ a: obj?.a.b } = { a: 1 });
({ ...obj?.a } = { a: 1 });
({ ...obj?.a.b } = { a: 1 });
[...obj?.a] = [];
[...obj?.a.b] = [];
@@ -0,0 +1,16 @@
// @strict: true
declare const o1: undefined | { b: string };
o1?.b;
declare const o2: undefined | { b: { c: string } };
o2?.b.c;
declare const o3: { b: undefined | { c: string } };
o3.b?.c;
declare const o4: { b?: { c: { d?: { e: string } } } };
o4.b?.c.d?.e;
declare const o5: { b?(): { c: { d?: { e: string } } } };
o5.b?.().c.d?.e;
@@ -0,0 +1,4 @@
declare let a: any;
a?.`b`;
a?.`b${1}c`;
@@ -0,0 +1,20 @@
/// <reference path="fourslash.ts" />
// @strict: true
//// interface User {
//// address?: {
//// city: string;
//// "postal code": string;
//// }
//// };
//// declare const user: User;
//// user.address[|?./**/|]
verify.completions({
marker: "",
exact: [
{ name: "city", text: "(property) city: string" },
{ name: "postal code", text: "(property) \"postal code\": string", insertText: "?.[\"postal code\"]", replacementSpan: test.ranges()[0] }
],
preferences: { includeInsertTextCompletions: true },
});
@@ -0,0 +1,20 @@
/// <reference path="fourslash.ts" />
// @strict: true
//// interface User {
//// address?: {
//// city: string;
//// "postal code": string;
//// }
//// };
//// declare const user: User;
//// user.address[|./**/|]
verify.completions({
marker: "",
exact: [
{ name: "city", text: "(property) city: string", insertText: "?.city", replacementSpan: test.ranges()[0] },
{ name: "postal code", text: "(property) \"postal code\": string", insertText: "?.[\"postal code\"]", replacementSpan: test.ranges()[0] }
],
preferences: { includeInsertTextCompletions: true },
});
@@ -0,0 +1,20 @@
/// <reference path="fourslash.ts" />
// @strict: true
//// class Address {
//// city: string = "";
//// "postal code": string = "";
//// method() {
//// this[|./**/|]
//// }
//// }
verify.completions({
marker: "",
exact: [
{ name: "city", text: "(property) Address.city: string", insertText: undefined },
{ name: "postal code", text: "(property) Address[\"postal code\"]: string", insertText: "[\"postal code\"]", replacementSpan: test.ranges()[0] },
{ name: "method" }
],
preferences: { includeInsertTextCompletions: true },
});
@@ -0,0 +1,19 @@
/// <reference path="fourslash.ts" />
// @strict: true
//// interface Address {
//// city: string = "";
//// "postal code": string = "";
//// }
//// function f<T extends Address>(x: T) {
//// x[|./**/|]
//// }
verify.completions({
marker: "",
exact: [
{ name: "city", text: "(property) Address.city: string" },
{ name: "postal code", text: "(property) Address[\"postal code\"]: string", insertText: "[\"postal code\"]", replacementSpan: test.ranges()[0] }
],
preferences: { includeInsertTextCompletions: true },
});
@@ -0,0 +1,14 @@
/// <reference path='fourslash.ts'/>
////function fnTest(str: string, num: number) { }
////fnTest?.(/*1*/);
verify.signatureHelp(
{
marker: "1",
text: 'fnTest(str: string, num: number): void',
parameterCount: 2,
parameterName: "str",
parameterSpan: "str: string",
},
);
@@ -0,0 +1,14 @@
/// <reference path='fourslash.ts'/>
////declare const fnTest: undefined | ((str: string, num: number) => void);
////fnTest?.(/*1*/);
verify.signatureHelp(
{
marker: "1",
text: 'fnTest(str: string, num: number): void',
parameterCount: 2,
parameterName: "str",
parameterSpan: "str: string",
},
);