mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
parse, emit, initial check for optional chaining
This commit is contained in:
+19
-14
@@ -2674,11 +2674,24 @@ namespace ts {
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
return computePropertyAccess(<PropertyAccessExpression>node, subtreeFlags);
|
||||
|
||||
case SyntaxKind.CallChain:
|
||||
return computeCallChain(<CallChain>node, subtreeFlags);
|
||||
|
||||
default:
|
||||
return computeOther(node, kind, subtreeFlags);
|
||||
}
|
||||
}
|
||||
|
||||
function computeCallChain(node: CallChain, subtreeFlags: TransformFlags) {
|
||||
let transformFlags = subtreeFlags;
|
||||
if (node.typeArguments) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
|
||||
return transformFlags & ~TransformFlags.ArrayLiteralOrCallOrNewExcludes;
|
||||
}
|
||||
|
||||
function computeCallExpression(node: CallExpression, subtreeFlags: TransformFlags) {
|
||||
let transformFlags = subtreeFlags;
|
||||
const expression = node.expression;
|
||||
@@ -2688,10 +2701,6 @@ namespace ts {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
if (node.flags & NodeFlags.Optional) {
|
||||
transformFlags |= TransformFlags.AssertESNext;
|
||||
}
|
||||
|
||||
if (subtreeFlags & TransformFlags.ContainsSpread
|
||||
|| isSuperOrSuperProperty(expression, expressionKind)) {
|
||||
// If the this node contains a SpreadExpression, or is a super call, then it is an ES6
|
||||
@@ -3136,10 +3145,6 @@ namespace ts {
|
||||
const expression = node.expression;
|
||||
const expressionKind = expression.kind;
|
||||
|
||||
if (node.flags & NodeFlags.Optional) {
|
||||
transformFlags |= TransformFlags.AssertESNext;
|
||||
}
|
||||
|
||||
// If a PropertyAccessExpression starts with a super keyword, then it is
|
||||
// ES6 syntax, and requires a lexical `this` binding.
|
||||
if (expressionKind === SyntaxKind.SuperKeyword) {
|
||||
@@ -3296,6 +3301,12 @@ namespace ts {
|
||||
transformFlags |= TransformFlags.AssertJsx;
|
||||
break;
|
||||
|
||||
case SyntaxKind.OptionalExpression:
|
||||
case SyntaxKind.PropertyAccessChain:
|
||||
case SyntaxKind.ElementAccessChain:
|
||||
transformFlags |= TransformFlags.AssertESNext;
|
||||
break;
|
||||
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.TemplateHead:
|
||||
case SyntaxKind.TemplateMiddle:
|
||||
@@ -3466,12 +3477,6 @@ namespace ts {
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
if (node.flags & NodeFlags.Optional) {
|
||||
transformFlags |= TransformFlags.AssertESNext;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
|
||||
+93
-111
@@ -251,7 +251,6 @@ namespace ts {
|
||||
const unknownType = createIntrinsicType(TypeFlags.Any, "unknown");
|
||||
const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
|
||||
const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined");
|
||||
const optionalType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.Optional | TypeFlags.ContainsWideningType, "undefined");
|
||||
const nullType = createIntrinsicType(TypeFlags.Null, "null");
|
||||
const nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null | TypeFlags.ContainsWideningType, "null");
|
||||
const stringType = createIntrinsicType(TypeFlags.String, "string");
|
||||
@@ -380,21 +379,19 @@ namespace ts {
|
||||
TypeofNEFunction = 1 << 12, // typeof x !== "function"
|
||||
TypeofNEHostObject = 1 << 13, // typeof x !== "xxx"
|
||||
EQUndefined = 1 << 14, // x === undefined
|
||||
EQOptional = 1 << 15,
|
||||
EQNull = 1 << 16, // x === null
|
||||
EQUndefinedOrNull = 1 << 17, // x === undefined / x === null
|
||||
NEUndefined = 1 << 18, // x !== undefined
|
||||
NEOptional = 1 << 19,
|
||||
NENull = 1 << 20, // x !== null
|
||||
NEUndefinedOrNull = 1 << 21, // x != undefined / x != null
|
||||
Truthy = 1 << 22, // x
|
||||
Falsy = 1 << 23, // !x
|
||||
Discriminatable = 1 << 24, // May have discriminant property
|
||||
All = (1 << 25) - 1,
|
||||
EQNull = 1 << 15, // x === null
|
||||
EQUndefinedOrNull = 1 << 16, // x === undefined / x === null
|
||||
NEUndefined = 1 << 17, // x !== undefined
|
||||
NENull = 1 << 18, // x !== null
|
||||
NEUndefinedOrNull = 1 << 19, // x != undefined / x != null
|
||||
Truthy = 1 << 20, // x
|
||||
Falsy = 1 << 21, // !x
|
||||
Discriminatable = 1 << 22, // May have discriminant property
|
||||
All = (1 << 23) - 1,
|
||||
// The following members encode facts about particular kinds of types for use in the getTypeFacts function.
|
||||
// The presence of a particular fact means that the given test is true for some (and possibly all) values
|
||||
// of that kind of type.
|
||||
BaseStringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEOptional | NEUndefinedOrNull,
|
||||
BaseStringStrictFacts = TypeofEQString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull,
|
||||
BaseStringFacts = BaseStringStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
|
||||
StringStrictFacts = BaseStringStrictFacts | Truthy | Falsy,
|
||||
StringFacts = BaseStringFacts | Truthy,
|
||||
@@ -402,7 +399,7 @@ namespace ts {
|
||||
EmptyStringFacts = BaseStringFacts,
|
||||
NonEmptyStringStrictFacts = BaseStringStrictFacts | Truthy,
|
||||
NonEmptyStringFacts = BaseStringFacts | Truthy,
|
||||
BaseNumberStrictFacts = TypeofEQNumber | TypeofNEString | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEOptional | NEUndefinedOrNull,
|
||||
BaseNumberStrictFacts = TypeofEQNumber | TypeofNEString | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull,
|
||||
BaseNumberFacts = BaseNumberStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
|
||||
NumberStrictFacts = BaseNumberStrictFacts | Truthy | Falsy,
|
||||
NumberFacts = BaseNumberFacts | Truthy,
|
||||
@@ -410,7 +407,7 @@ namespace ts {
|
||||
ZeroFacts = BaseNumberFacts,
|
||||
NonZeroStrictFacts = BaseNumberStrictFacts | Truthy,
|
||||
NonZeroFacts = BaseNumberFacts | Truthy,
|
||||
BaseBooleanStrictFacts = TypeofEQBoolean | TypeofNEString | TypeofNENumber | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEOptional | NEUndefinedOrNull,
|
||||
BaseBooleanStrictFacts = TypeofEQBoolean | TypeofNEString | TypeofNENumber | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull,
|
||||
BaseBooleanFacts = BaseBooleanStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
|
||||
BooleanStrictFacts = BaseBooleanStrictFacts | Truthy | Falsy,
|
||||
BooleanFacts = BaseBooleanFacts | Truthy,
|
||||
@@ -418,15 +415,14 @@ namespace ts {
|
||||
FalseFacts = BaseBooleanFacts,
|
||||
TrueStrictFacts = BaseBooleanStrictFacts | Truthy,
|
||||
TrueFacts = BaseBooleanFacts | Truthy,
|
||||
SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEOptional | NEUndefinedOrNull | Truthy,
|
||||
SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy,
|
||||
SymbolFacts = SymbolStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
|
||||
ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEOptional | NEUndefinedOrNull | Truthy | Discriminatable,
|
||||
ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Discriminatable,
|
||||
ObjectFacts = ObjectStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
|
||||
FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEOptional | NEUndefinedOrNull | Truthy | Discriminatable,
|
||||
FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Discriminatable,
|
||||
FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
|
||||
UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | NEOptional | Falsy,
|
||||
OptionalFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQOptional | EQUndefinedOrNull | NENull | Falsy,
|
||||
NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | NEOptional | Falsy,
|
||||
UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy,
|
||||
NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy,
|
||||
}
|
||||
|
||||
const typeofEQFacts = createMapFromTemplate({
|
||||
@@ -7613,7 +7609,7 @@ namespace ts {
|
||||
return type;
|
||||
}
|
||||
|
||||
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean) {
|
||||
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | ElementAccessChain | IndexedAccessTypeNode, cacheSymbol: boolean) {
|
||||
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? <ElementAccessExpression>accessNode : undefined;
|
||||
const propName = indexType.flags & TypeFlags.StringOrNumberLiteral ?
|
||||
escapeLeadingUnderscores("" + (<LiteralType>indexType).value) :
|
||||
@@ -7661,7 +7657,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
if (accessNode) {
|
||||
const indexNode = accessNode.kind === SyntaxKind.ElementAccessExpression ? (<ElementAccessExpression>accessNode).argumentExpression : (<IndexedAccessTypeNode>accessNode).indexType;
|
||||
const indexNode = accessNode.kind === SyntaxKind.IndexedAccessType ? (<IndexedAccessTypeNode>accessNode).indexType : (<ElementAccessExpression | ElementAccessChain>accessNode).argumentExpression;
|
||||
if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
|
||||
error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, "" + (<LiteralType>indexType).value, typeToString(objectType));
|
||||
}
|
||||
@@ -7737,13 +7733,14 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode): Type {
|
||||
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | ElementAccessChain | IndexedAccessTypeNode): Type {
|
||||
// If the index type is generic, or if the object type is generic and doesn't originate in an expression,
|
||||
// we are performing a higher-order index access where we cannot meaningfully access the properties of the
|
||||
// object type. Note that for a generic T and a non-generic K, we eagerly resolve T[K] if it originates in
|
||||
// an expression. This is to preserve backwards compatibility. For example, an element access 'this["foo"]'
|
||||
// has always been resolved eagerly using the constraint type of 'this' at the given location.
|
||||
if (isGenericIndexType(indexType) || !(accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression) && isGenericObjectType(objectType)) {
|
||||
if (isGenericIndexType(indexType) || !(accessNode && (accessNode.kind === SyntaxKind.ElementAccessExpression || accessNode.kind === SyntaxKind.ElementAccessChain)) &&
|
||||
isGenericObjectType(objectType)) {
|
||||
if (objectType.flags & TypeFlags.Any) {
|
||||
return objectType;
|
||||
}
|
||||
@@ -10153,10 +10150,6 @@ namespace ts {
|
||||
return strictNullChecks ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type;
|
||||
}
|
||||
|
||||
function getNonOptionalType(type: Type): Type {
|
||||
return strictNullChecks ? getTypeWithFacts(type, TypeFacts.NEOptional) : type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if type was inferred from an object literal or written as an object type literal
|
||||
* with no call or construct signatures.
|
||||
@@ -10243,9 +10236,6 @@ namespace ts {
|
||||
|
||||
function getWidenedType(type: Type): Type {
|
||||
if (type.flags & TypeFlags.RequiresWidening) {
|
||||
if (type.flags & TypeFlags.Optional) {
|
||||
return strictNullChecks ? undefinedType : anyType;
|
||||
}
|
||||
if (type.flags & TypeFlags.Nullable) {
|
||||
return anyType;
|
||||
}
|
||||
@@ -11109,7 +11099,7 @@ namespace ts {
|
||||
strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
|
||||
}
|
||||
if (flags & (TypeFlags.Void | TypeFlags.Undefined)) {
|
||||
return flags & TypeFlags.Optional ? TypeFacts.OptionalFacts : TypeFacts.UndefinedFacts;
|
||||
return TypeFacts.UndefinedFacts;
|
||||
}
|
||||
if (flags & TypeFlags.Null) {
|
||||
return TypeFacts.NullFacts;
|
||||
@@ -14609,14 +14599,14 @@ namespace ts {
|
||||
* Check whether the requested property access is valid.
|
||||
* Returns true if node is a valid property access, and false otherwise.
|
||||
* @param node The node to be checked.
|
||||
* @param left The left hand side of the property access (e.g.: the super in `super.foo`).
|
||||
* @param isSuperProperty Whether the left hand side of the property access is `super`.
|
||||
* @param type The type of left.
|
||||
* @param prop The symbol for the right hand side of the property access.
|
||||
*/
|
||||
function checkPropertyAccessibility(node: PropertyAccessExpression | QualifiedName | VariableLikeDeclaration, left: Expression | QualifiedName, type: Type, prop: Symbol): boolean {
|
||||
function checkPropertyAccessibility(node: PropertyAccessExpression | PropertyAccessChain | QualifiedName | VariableLikeDeclaration, isSuperProperty: boolean, type: Type, prop: Symbol): boolean {
|
||||
const flags = getDeclarationModifierFlagsFromSymbol(prop);
|
||||
const errorNode = node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.VariableDeclaration ?
|
||||
(<PropertyAccessExpression | VariableDeclaration>node).name :
|
||||
const errorNode = node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.PropertyAccessChain ?
|
||||
(<PropertyAccessExpression | PropertyAccessChain | VariableDeclaration>node).name :
|
||||
(<QualifiedName>node).right;
|
||||
|
||||
if (getCheckFlags(prop) & CheckFlags.ContainsPrivate) {
|
||||
@@ -14625,7 +14615,7 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (left.kind === SyntaxKind.SuperKeyword) {
|
||||
if (isSuperProperty) {
|
||||
// TS 1.0 spec (April 2014): 4.8.2
|
||||
// - In a constructor, instance member function, instance member accessor, or
|
||||
// instance member variable initializer where this references a derived class instance,
|
||||
@@ -14673,7 +14663,7 @@ namespace ts {
|
||||
// Property is known to be protected at this point
|
||||
|
||||
// All protected properties of a supertype are accessible in a super access
|
||||
if (left.kind === SyntaxKind.SuperKeyword) {
|
||||
if (isSuperProperty) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -14708,14 +14698,7 @@ namespace ts {
|
||||
return checkNonNullType(checkExpression(node), node);
|
||||
}
|
||||
|
||||
function checkNonNullType(type: Type, errorNode: Node, optionality?: NodeFlags): Type {
|
||||
if (optionality & NodeFlags.OptionalExpression) {
|
||||
type = getNonNullableType(type);
|
||||
}
|
||||
else if (optionality & NodeFlags.OptionalChain) {
|
||||
type = getNonOptionalType(type);
|
||||
}
|
||||
|
||||
function checkNonNullType(type: Type, errorNode: Node): Type {
|
||||
const kind = (strictNullChecks ? getFalsyFlags(type) : type.flags) & TypeFlags.Nullable;
|
||||
if (kind) {
|
||||
error(errorNode, kind & TypeFlags.Undefined ? kind & TypeFlags.Null ?
|
||||
@@ -14729,51 +14712,20 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkPropertyAccessExpression(node: PropertyAccessExpression) {
|
||||
return checkPropertyAccessExpressionOrQualifiedName(node, node.expression, node.name);
|
||||
return checkPropertyAccessExpressionOrQualifiedName(node, checkNonNullExpression(node.expression), node.name, node.expression.kind === SyntaxKind.SuperKeyword);
|
||||
}
|
||||
|
||||
function checkQualifiedName(node: QualifiedName) {
|
||||
return checkPropertyAccessExpressionOrQualifiedName(node, node.left, node.right);
|
||||
return checkPropertyAccessExpressionOrQualifiedName(node, checkNonNullExpression(node.left), node.right, /*isSuperProperty*/ false);
|
||||
}
|
||||
|
||||
// function checkOptionality(node: Node) {
|
||||
// if (node.flags & NodeFlags.OptionalExpression) {
|
||||
// if (!compilerOptions.experimentalOptionalChaining) {
|
||||
// error(node, Diagnostics.Experimental_support_for_optional_chaining_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalOptionalChaining_option_to_remove_this_warning);
|
||||
// }
|
||||
// return strictNullChecks;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
function propagateOptionalChain(type: Type, sourceType: Type, optionality: NodeFlags) {
|
||||
const expectedFacts = optionality & NodeFlags.OptionalExpression ? TypeFacts.EQUndefinedOrNull : TypeFacts.EQOptional;
|
||||
return optionality && strictNullChecks && getTypeFacts(sourceType) & expectedFacts
|
||||
? getUnionType([type, optionalType])
|
||||
: type;
|
||||
}
|
||||
|
||||
function propagateOptionalChainSignature(signature: Signature, sourceType: Type, optionality: NodeFlags) {
|
||||
const expectedFacts = optionality & NodeFlags.OptionalExpression ? TypeFacts.EQUndefinedOrNull : TypeFacts.EQOptional;
|
||||
if (optionality && strictNullChecks && getTypeFacts(sourceType) & expectedFacts) {
|
||||
signature = cloneSignature(signature);
|
||||
signature.resolvedReturnType = getUnionType([getReturnTypeOfSignature(signature), optionalType]);
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
|
||||
// if a node is an OptionalExpression, use its non-null type
|
||||
const optionality = node.flags & NodeFlags.Optional;
|
||||
const sourceType = checkExpression(left);
|
||||
const type = checkNonNullType(sourceType, left, optionality);
|
||||
|
||||
if (isTypeAny(type) || type === silentNeverType) {
|
||||
return type;
|
||||
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | PropertyAccessChain | QualifiedName, leftType: Type, right: Identifier, isSuperProperty: boolean) {
|
||||
if (isTypeAny(leftType) || leftType === silentNeverType) {
|
||||
return leftType;
|
||||
}
|
||||
|
||||
const apparentType = getApparentType(getWidenedType(type));
|
||||
if (apparentType === unknownType || (type.flags & TypeFlags.TypeParameter && isTypeAny(apparentType))) {
|
||||
const apparentType = getApparentType(getWidenedType(leftType));
|
||||
if (apparentType === unknownType || (leftType.flags & TypeFlags.TypeParameter && isTypeAny(apparentType))) {
|
||||
// handle cases when type is Type parameter with invalid or any constraint
|
||||
return apparentType;
|
||||
}
|
||||
@@ -14787,7 +14739,7 @@ namespace ts {
|
||||
return indexInfo.type;
|
||||
}
|
||||
if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) {
|
||||
reportNonexistentProperty(right, type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType ? apparentType : type);
|
||||
reportNonexistentProperty(right, leftType.flags & TypeFlags.TypeParameter && (leftType as TypeParameter).isThisType ? apparentType : leftType);
|
||||
}
|
||||
return unknownType;
|
||||
}
|
||||
@@ -14798,7 +14750,7 @@ namespace ts {
|
||||
|
||||
getNodeLinks(node).resolvedSymbol = prop;
|
||||
|
||||
checkPropertyAccessibility(node, left, apparentType, prop);
|
||||
checkPropertyAccessibility(node, isSuperProperty, apparentType, prop);
|
||||
|
||||
const propType = getDeclaredOrApparentType(prop, node);
|
||||
const assignmentKind = getAssignmentTargetKind(node);
|
||||
@@ -14816,14 +14768,13 @@ namespace ts {
|
||||
if (node.kind !== SyntaxKind.PropertyAccessExpression || assignmentKind === AssignmentKind.Definite ||
|
||||
!(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) &&
|
||||
!(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) {
|
||||
return propagateOptionalChain(propType, sourceType, optionality);
|
||||
return propType;
|
||||
}
|
||||
const flowType = getFlowTypeOfReference(node, propType);
|
||||
const resultType = assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType;
|
||||
return propagateOptionalChain(resultType, sourceType, optionality);
|
||||
return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType;
|
||||
}
|
||||
|
||||
function checkPropertyNotUsedBeforeDeclaration(prop: Symbol, node: PropertyAccessExpression | QualifiedName, right: Identifier): void {
|
||||
function checkPropertyNotUsedBeforeDeclaration(prop: Symbol, node: PropertyAccessExpression | PropertyAccessChain | QualifiedName, right: Identifier): void {
|
||||
const { valueDeclaration } = prop;
|
||||
if (!valueDeclaration) {
|
||||
return;
|
||||
@@ -15021,7 +14972,7 @@ namespace ts {
|
||||
if (type !== unknownType && !isTypeAny(type)) {
|
||||
const prop = getPropertyOfType(type, propertyName);
|
||||
if (prop) {
|
||||
return checkPropertyAccessibility(node, left, type, prop);
|
||||
return checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, type, prop);
|
||||
}
|
||||
|
||||
// In js files properties of unions are allowed in completion
|
||||
@@ -15089,10 +15040,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkIndexedAccess(node: ElementAccessExpression): Type {
|
||||
const optionality = node.flags & NodeFlags.Optional;
|
||||
const sourceType = checkExpression(node.expression);
|
||||
const objectType = checkNonNullType(sourceType, node.expression, optionality);
|
||||
const objectType = checkNonNullExpression(node.expression);
|
||||
return checkIndexedAccessWorker(node, objectType);
|
||||
}
|
||||
|
||||
function checkIndexedAccessWorker(node: ElementAccessExpression | ElementAccessChain, objectType: Type) {
|
||||
const indexExpression = node.argumentExpression;
|
||||
if (!indexExpression) {
|
||||
const sourceFile = getSourceFileOfNode(node);
|
||||
@@ -15120,8 +15072,7 @@ namespace ts {
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
const resultType = checkIndexedAccessIndexType(getIndexedAccessType(objectType, indexType, node), node);
|
||||
return propagateOptionalChain(resultType, objectType, optionality);
|
||||
return checkIndexedAccessIndexType(getIndexedAccessType(objectType, indexType, node), node);
|
||||
}
|
||||
|
||||
function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean {
|
||||
@@ -15166,6 +15117,34 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getLeftTypeOfOptionalChain(node: OptionalChain) {
|
||||
if (node.chain) return checkOptionalChain(node.chain);
|
||||
const optionalExpression = findAncestor(node, isOptionalExpression);
|
||||
const type = checkExpressionCached(optionalExpression.expression);
|
||||
return getNonNullableType(type);
|
||||
}
|
||||
|
||||
function checkOptionalChain(node: OptionalChain): Type {
|
||||
const objectType = getLeftTypeOfOptionalChain(node);
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.PropertyAccessChain:
|
||||
return checkPropertyAccessExpressionOrQualifiedName(node, objectType, node.name, /*isSuperProperty*/ false);
|
||||
case SyntaxKind.ElementAccessChain:
|
||||
return checkIndexedAccessWorker(node, objectType);
|
||||
case SyntaxKind.CallChain:
|
||||
return checkCallExpression(node);
|
||||
}
|
||||
}
|
||||
|
||||
function checkOptionalExpression(node: OptionalExpression) {
|
||||
const type = checkExpression(node.expression);
|
||||
const chainType = checkOptionalChain(node.chain);
|
||||
if ((strictNullChecks ? getFalsyFlags(type) : type.flags) & TypeFlags.Nullable) {
|
||||
return getNullableType(chainType, TypeFlags.Undefined);
|
||||
}
|
||||
return chainType;
|
||||
}
|
||||
|
||||
function callLikeExpressionMayHaveTypeArguments(node: CallLikeExpression): node is CallExpression | NewExpression {
|
||||
// TODO: Also include tagged templates (https://github.com/Microsoft/TypeScript/issues/11947)
|
||||
return isCallOrNewExpression(node);
|
||||
@@ -15383,7 +15362,10 @@ namespace ts {
|
||||
// example, given a 'function wrap<T, U>(cb: (x: T) => U): (x: T) => U' and a call expression
|
||||
// 'let f: (x: string) => number = wrap(s => s.length)', we infer from the declared type of 'f' to the
|
||||
// return type of 'wrap'.
|
||||
if (node.kind !== SyntaxKind.Decorator) {
|
||||
if (node.kind === SyntaxKind.CallChain) {
|
||||
sys.write("TODO: getContextualTypeOfCallChain");
|
||||
}
|
||||
else if (node.kind !== SyntaxKind.Decorator) {
|
||||
const contextualType = getContextualType(node);
|
||||
if (contextualType) {
|
||||
// We clone the contextual mapper to avoid disturbing a resolution in progress for an
|
||||
@@ -16168,8 +16150,8 @@ namespace ts {
|
||||
return maxParamsIndex;
|
||||
}
|
||||
|
||||
function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[]): Signature {
|
||||
if (node.expression.kind === SyntaxKind.SuperKeyword) {
|
||||
function resolveCallExpression(node: CallExpression | CallChain, candidatesOutArray: Signature[]): Signature {
|
||||
if (node.kind !== SyntaxKind.CallChain && node.expression.kind === SyntaxKind.SuperKeyword) {
|
||||
const superType = checkSuperExpression(node.expression);
|
||||
if (superType !== unknownType) {
|
||||
// In super call, the candidate signatures are the matching arity signatures of the base constructor function instantiated
|
||||
@@ -16183,9 +16165,7 @@ namespace ts {
|
||||
return resolveUntypedCall(node);
|
||||
}
|
||||
|
||||
const optionality = node.flags & NodeFlags.Optional;
|
||||
const sourceType = checkExpression(node.expression);
|
||||
const funcType = checkNonNullType(sourceType, node.expression, optionality);
|
||||
const funcType = node.kind === SyntaxKind.CallChain ? getLeftTypeOfOptionalChain(node) : checkNonNullExpression(node.expression);
|
||||
if (funcType === silentNeverType) {
|
||||
return silentNeverSignature;
|
||||
}
|
||||
@@ -16226,9 +16206,7 @@ namespace ts {
|
||||
}
|
||||
return resolveErrorCall(node);
|
||||
}
|
||||
|
||||
const signature = resolveCall(node, callSignatures, candidatesOutArray);
|
||||
return propagateOptionalChainSignature(signature, sourceType, optionality);
|
||||
return resolveCall(node, callSignatures, candidatesOutArray);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -16495,7 +16473,8 @@ namespace ts {
|
||||
function resolveSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.CallExpression:
|
||||
return resolveCallExpression(<CallExpression>node, candidatesOutArray);
|
||||
case SyntaxKind.CallChain:
|
||||
return resolveCallExpression(node, candidatesOutArray);
|
||||
case SyntaxKind.NewExpression:
|
||||
return resolveNewExpression(<NewExpression>node, candidatesOutArray);
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
@@ -16590,13 +16569,14 @@ namespace ts {
|
||||
* @param node The call/new expression to be checked.
|
||||
* @returns On success, the expression's signature's return type. On failure, anyType.
|
||||
*/
|
||||
function checkCallExpression(node: CallExpression | NewExpression): Type {
|
||||
function checkCallExpression(node: CallExpression | CallChain | NewExpression): Type {
|
||||
// Grammar checking; stop grammar-checking if checkGrammarTypeArguments return true
|
||||
checkGrammarTypeArguments(node, node.typeArguments) || checkGrammarArguments(node.arguments);
|
||||
|
||||
const signature = getResolvedSignature(node);
|
||||
|
||||
if (node.expression.kind === SyntaxKind.SuperKeyword) {
|
||||
const isSuper = node.kind !== SyntaxKind.CallChain && node.expression.kind === SyntaxKind.SuperKeyword;
|
||||
if (isSuper) {
|
||||
return voidType;
|
||||
}
|
||||
|
||||
@@ -18225,6 +18205,8 @@ namespace ts {
|
||||
return checkPropertyAccessExpression(<PropertyAccessExpression>node);
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
return checkIndexedAccess(<ElementAccessExpression>node);
|
||||
case SyntaxKind.OptionalExpression:
|
||||
return checkOptionalExpression(<OptionalExpression>node);
|
||||
case SyntaxKind.CallExpression:
|
||||
if ((<CallExpression>node).expression.kind === SyntaxKind.ImportKeyword) {
|
||||
return checkImportCallExpression(<ImportCall>node);
|
||||
@@ -18973,7 +18955,7 @@ namespace ts {
|
||||
forEach(node.types, checkSourceElement);
|
||||
}
|
||||
|
||||
function checkIndexedAccessIndexType(type: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode) {
|
||||
function checkIndexedAccessIndexType(type: Type, accessNode: ElementAccessExpression | ElementAccessChain | IndexedAccessTypeNode) {
|
||||
if (!(type.flags & TypeFlags.IndexedAccess)) {
|
||||
return type;
|
||||
}
|
||||
@@ -20436,7 +20418,7 @@ namespace ts {
|
||||
const property = getPropertyOfType(parentType, getTextOfPropertyName(name));
|
||||
markPropertyAsReferenced(property, /*nodeForCheckWriteOnly*/ undefined); // A destructuring is never a write-only reference.
|
||||
if (parent.initializer && property) {
|
||||
checkPropertyAccessibility(parent, parent.initializer, parentType, property);
|
||||
checkPropertyAccessibility(parent, /*isSuperProperty*/ false, parentType, property);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+55
-7
@@ -583,6 +583,14 @@ namespace ts {
|
||||
case SyntaxKind.BindingElement:
|
||||
return emitBindingElement(<BindingElement>node);
|
||||
|
||||
// Optional chains
|
||||
case SyntaxKind.PropertyAccessChain:
|
||||
return emitPropertyAccessChain(<PropertyAccessChain>node);
|
||||
case SyntaxKind.ElementAccessChain:
|
||||
return emitElementAccessChain(<ElementAccessChain>node);
|
||||
case SyntaxKind.CallChain:
|
||||
return emitCallChain(<CallChain>node);
|
||||
|
||||
// Misc
|
||||
case SyntaxKind.TemplateSpan:
|
||||
return emitTemplateSpan(<TemplateSpan>node);
|
||||
@@ -768,6 +776,8 @@ namespace ts {
|
||||
return emitPropertyAccessExpression(<PropertyAccessExpression>node);
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
return emitElementAccessExpression(<ElementAccessExpression>node);
|
||||
case SyntaxKind.OptionalExpression:
|
||||
return emitOptionalExpression(<OptionalExpression>node);
|
||||
case SyntaxKind.CallExpression:
|
||||
return emitCallExpression(<CallExpression>node);
|
||||
case SyntaxKind.NewExpression:
|
||||
@@ -1195,13 +1205,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
function emitPropertyAccessExpression(node: PropertyAccessExpression) {
|
||||
const isOptionalExpression = node.flags & NodeFlags.OptionalExpression;
|
||||
let indentBeforeDot = false;
|
||||
let indentAfterDot = false;
|
||||
if (!(getEmitFlags(node) & EmitFlags.NoIndentation)) {
|
||||
const dotRangeStart = node.expression.end;
|
||||
const dotRangeEnd = skipTrivia(currentSourceFile.text, node.expression.end) + 1;
|
||||
const dotToken = createToken(isOptionalExpression ? SyntaxKind.QuestionDotToken : SyntaxKind.DotToken);
|
||||
const dotToken = createToken(SyntaxKind.DotToken);
|
||||
dotToken.pos = dotRangeStart;
|
||||
dotToken.end = dotRangeEnd;
|
||||
indentBeforeDot = needsIndentation(node, node.expression, dotToken);
|
||||
@@ -1211,8 +1220,8 @@ namespace ts {
|
||||
emitExpression(node.expression);
|
||||
increaseIndentIf(indentBeforeDot);
|
||||
|
||||
const shouldEmitDotDot = !isOptionalExpression && !indentBeforeDot && needsDotDotForPropertyAccess(node.expression);
|
||||
write(shouldEmitDotDot ? ".." : isOptionalExpression ? "?." : ".");
|
||||
const shouldEmitDotDot = !indentBeforeDot && needsDotDotForPropertyAccess(node.expression);
|
||||
write(shouldEmitDotDot ? ".." : ".");
|
||||
|
||||
increaseIndentIf(indentAfterDot);
|
||||
emit(node.name);
|
||||
@@ -1241,16 +1250,55 @@ namespace ts {
|
||||
|
||||
function emitElementAccessExpression(node: ElementAccessExpression) {
|
||||
emitExpression(node.expression);
|
||||
write(node.flags & NodeFlags.OptionalExpression ? "?.[" : "[");
|
||||
write("[");
|
||||
emitExpression(node.argumentExpression);
|
||||
write("]");
|
||||
}
|
||||
|
||||
function emitCallExpression(node: CallExpression) {
|
||||
function emitOptionalExpression(node: OptionalExpression) {
|
||||
emitExpression(node.expression);
|
||||
if (node.flags & NodeFlags.OptionalExpression) {
|
||||
emit(node.chain);
|
||||
}
|
||||
|
||||
function emitPropertyAccessChain(node: PropertyAccessChain) {
|
||||
if (node.chain) {
|
||||
emit(node.chain);
|
||||
write(".");
|
||||
}
|
||||
else {
|
||||
write("?.");
|
||||
}
|
||||
|
||||
emit(node.name);
|
||||
}
|
||||
|
||||
function emitElementAccessChain(node: ElementAccessChain) {
|
||||
if (node.chain) {
|
||||
emit(node.chain);
|
||||
}
|
||||
else {
|
||||
write("?.");
|
||||
}
|
||||
|
||||
write("[");
|
||||
emitExpression(node.argumentExpression);
|
||||
write("]");
|
||||
}
|
||||
|
||||
function emitCallChain(node: CallChain) {
|
||||
if (node.chain) {
|
||||
emit(node.chain);
|
||||
}
|
||||
else {
|
||||
write("?.");
|
||||
}
|
||||
|
||||
emitTypeArguments(node, node.typeArguments);
|
||||
emitExpressionList(node, node.arguments, ListFormat.CallExpressionArguments);
|
||||
}
|
||||
|
||||
function emitCallExpression(node: CallExpression) {
|
||||
emitExpression(node.expression);
|
||||
emitTypeArguments(node, node.typeArguments);
|
||||
emitExpressionList(node, node.arguments, ListFormat.CallExpressionArguments);
|
||||
}
|
||||
|
||||
+58
-7
@@ -859,7 +859,6 @@ namespace ts {
|
||||
|
||||
export function createPropertyAccess(expression: Expression, name: string | Identifier) {
|
||||
const node = <PropertyAccessExpression>createSynthesizedNode(SyntaxKind.PropertyAccessExpression);
|
||||
if (expression.flags & NodeFlags.Optional) node.flags |= NodeFlags.OptionalChain;
|
||||
node.expression = parenthesizeForAccess(expression);
|
||||
node.name = asName(name);
|
||||
setEmitFlags(node, EmitFlags.NoIndentation);
|
||||
@@ -877,7 +876,6 @@ namespace ts {
|
||||
|
||||
export function createElementAccess(expression: Expression, index: number | Expression) {
|
||||
const node = <ElementAccessExpression>createSynthesizedNode(SyntaxKind.ElementAccessExpression);
|
||||
if (expression.flags & NodeFlags.Optional) node.flags |= NodeFlags.OptionalChain;
|
||||
node.expression = parenthesizeForAccess(expression);
|
||||
node.argumentExpression = asExpression(index);
|
||||
return node;
|
||||
@@ -890,9 +888,66 @@ namespace ts {
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createOptionalExpression(expression: Expression, chain: OptionalChain) {
|
||||
const node = <OptionalExpression>createSynthesizedNode(SyntaxKind.ElementAccessExpression);
|
||||
node.expression = parenthesizeForAccess(expression);
|
||||
node.chain = chain;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateOptionalExpression(node: OptionalExpression, expression: Expression, chain: OptionalChain) {
|
||||
return node.expression !== expression
|
||||
|| node.chain !== chain
|
||||
? updateNode(createOptionalExpression(expression, chain), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createPropertyAccessChain(chain: OptionalChain | undefined, name: Identifier) {
|
||||
const node = <PropertyAccessChain>createSynthesizedNode(SyntaxKind.PropertyAccessChain);
|
||||
node.chain = chain;
|
||||
node.name = name;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updatePropertyAccessChain(node: PropertyAccessChain, chain: OptionalChain | undefined, name: Identifier) {
|
||||
return node.chain !== chain
|
||||
|| node.name !== name
|
||||
? updateNode(createPropertyAccessChain(chain, name), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createElementAccessChain(chain: OptionalChain | undefined, argumentExpression: Expression) {
|
||||
const node = <ElementAccessChain>createSynthesizedNode(SyntaxKind.ElementAccessChain);
|
||||
node.chain = chain;
|
||||
node.argumentExpression = argumentExpression;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateElementAccessChain(node: ElementAccessChain, chain: OptionalChain | undefined, argumentExpression: Expression) {
|
||||
return node.chain !== chain
|
||||
|| node.argumentExpression !== argumentExpression
|
||||
? updateNode(createElementAccessChain(chain, argumentExpression), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createCallChain(chain: OptionalChain | undefined, typeArguments: ReadonlyArray<TypeNode> | undefined, argumentList: ReadonlyArray<Expression>) {
|
||||
const node = <CallChain>createSynthesizedNode(SyntaxKind.CallChain);
|
||||
node.chain = chain;
|
||||
node.typeArguments = asNodeArray(typeArguments);
|
||||
node.arguments = createNodeArray(argumentList);
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateCallChain(node: CallChain, chain: OptionalChain | undefined, typeArguments: ReadonlyArray<TypeNode> | undefined, argumentList: ReadonlyArray<Expression>) {
|
||||
return node.chain !== chain
|
||||
|| node.typeArguments !== typeArguments
|
||||
|| node.arguments !== argumentList
|
||||
? updateNode(createCallChain(chain, typeArguments, argumentList), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createCall(expression: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, argumentsArray: ReadonlyArray<Expression>) {
|
||||
const node = <CallExpression>createSynthesizedNode(SyntaxKind.CallExpression);
|
||||
if (expression.flags & NodeFlags.Optional) node.flags |= NodeFlags.OptionalChain;
|
||||
node.expression = parenthesizeForAccess(expression);
|
||||
node.typeArguments = asNodeArray(typeArguments);
|
||||
node.arguments = parenthesizeListElements(createNodeArray(argumentsArray));
|
||||
@@ -2505,10 +2560,6 @@ namespace ts {
|
||||
return createBinary(left, SyntaxKind.EqualsToken, right);
|
||||
}
|
||||
|
||||
export function createEquality(left: Expression, right: Expression) {
|
||||
return createBinary(left, SyntaxKind.EqualsEqualsToken, right);
|
||||
}
|
||||
|
||||
export function createStrictEquality(left: Expression, right: Expression) {
|
||||
return createBinary(left, SyntaxKind.EqualsEqualsEqualsToken, right);
|
||||
}
|
||||
|
||||
+80
-58
@@ -170,6 +170,19 @@ namespace ts {
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
return visitNode(cbNode, (<ElementAccessExpression>node).expression) ||
|
||||
visitNode(cbNode, (<ElementAccessExpression>node).argumentExpression);
|
||||
case SyntaxKind.OptionalExpression:
|
||||
return visitNode(cbNode, (<OptionalExpression>node).expression) ||
|
||||
visitNode(cbNode, (<OptionalExpression>node).chain);
|
||||
case SyntaxKind.PropertyAccessChain:
|
||||
return visitNode(cbNode, (<PropertyAccessChain>node).chain) ||
|
||||
visitNode(cbNode, (<PropertyAccessChain>node).name);
|
||||
case SyntaxKind.ElementAccessChain:
|
||||
return visitNode(cbNode, (<ElementAccessChain>node).chain) ||
|
||||
visitNode(cbNode, (<ElementAccessChain>node).argumentExpression);
|
||||
case SyntaxKind.CallChain:
|
||||
return visitNode(cbNode, (<CallChain>node).chain) ||
|
||||
visitNodes(cbNode, cbNodes, (<CallChain>node).typeArguments) ||
|
||||
visitNodes(cbNode, cbNodes, (<CallChain>node).arguments);
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
return visitNode(cbNode, (<CallExpression>node).expression) ||
|
||||
@@ -2532,11 +2545,6 @@ namespace ts {
|
||||
return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken;
|
||||
}
|
||||
|
||||
function nextTokenIsOpenBracket() {
|
||||
nextToken();
|
||||
return token() === SyntaxKind.OpenBracketToken;
|
||||
}
|
||||
|
||||
function parseTypeLiteral(): TypeLiteralNode {
|
||||
const node = <TypeLiteralNode>createNode(SyntaxKind.TypeLiteral);
|
||||
node.members = parseObjectTypeMembers();
|
||||
@@ -3869,7 +3877,7 @@ 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.
|
||||
return parseCallExpressionRest(expression);
|
||||
return parseOptionalExpressionRest(parseCallExpressionRest(expression));
|
||||
}
|
||||
|
||||
function parseMemberExpressionOrHigher(): MemberExpression {
|
||||
@@ -4191,22 +4199,9 @@ namespace ts {
|
||||
|
||||
function parseMemberExpressionRest(expression: LeftHandSideExpression): MemberExpression {
|
||||
while (true) {
|
||||
const isOptionalExpression = token() === SyntaxKind.QuestionDotToken;
|
||||
const isOptionalCall = isOptionalExpression && lookAhead(nextTokenIsOpenParenOrLessThan);
|
||||
if (isOptionalCall) {
|
||||
// In an optional-chaining call or new expression, we defer parsing `.?` to parseCallExpressionRest.
|
||||
return <MemberExpression>expression;
|
||||
}
|
||||
|
||||
let flags: NodeFlags = NodeFlags.None;
|
||||
if (isOptionalExpression) flags |= NodeFlags.OptionalExpression;
|
||||
if (expression.flags & NodeFlags.Optional) flags |= NodeFlags.OptionalChain;
|
||||
|
||||
const isOptionalPropertyAccess = isOptionalExpression && !lookAhead(nextTokenIsOpenBracket);
|
||||
if (isOptionalPropertyAccess || token() === SyntaxKind.DotToken) {
|
||||
nextToken();
|
||||
const dotToken = parseOptionalToken(SyntaxKind.DotToken);
|
||||
if (dotToken) {
|
||||
const propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
|
||||
propertyAccess.flags = flags;
|
||||
propertyAccess.expression = expression;
|
||||
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
|
||||
expression = finishNode(propertyAccess);
|
||||
@@ -4216,18 +4211,14 @@ namespace ts {
|
||||
if (token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
|
||||
nextToken();
|
||||
const nonNullExpression = <NonNullExpression>createNode(SyntaxKind.NonNullExpression, expression.pos);
|
||||
nonNullExpression.flags = flags;
|
||||
nonNullExpression.expression = expression;
|
||||
expression = finishNode(nonNullExpression);
|
||||
continue;
|
||||
}
|
||||
|
||||
// when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName
|
||||
// however, `?.[` is unambiguously *not* a ComputedPropertyName.
|
||||
const isOptionalElementAccess = isOptionalExpression && !isOptionalPropertyAccess;
|
||||
if (isOptionalElementAccess || (!inDecoratorContext() && parseOptional(SyntaxKind.OpenBracketToken))) {
|
||||
if (!inDecoratorContext() && parseOptional(SyntaxKind.OpenBracketToken)) {
|
||||
const indexedAccess = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression, expression.pos);
|
||||
indexedAccess.flags = flags;
|
||||
indexedAccess.expression = expression;
|
||||
|
||||
// It's not uncommon for a user to write: "new Type[]".
|
||||
@@ -4247,7 +4238,6 @@ namespace ts {
|
||||
|
||||
if (token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead) {
|
||||
const tagExpression = <TaggedTemplateExpression>createNode(SyntaxKind.TaggedTemplateExpression, expression.pos);
|
||||
tagExpression.flags = flags;
|
||||
tagExpression.tag = expression;
|
||||
tagExpression.template = token() === SyntaxKind.NoSubstitutionTemplateLiteral
|
||||
? <NoSubstitutionTemplateLiteral>parseLiteralNode()
|
||||
@@ -4263,44 +4253,77 @@ namespace ts {
|
||||
function parseCallExpressionRest(expression: LeftHandSideExpression): LeftHandSideExpression {
|
||||
while (true) {
|
||||
expression = parseMemberExpressionRest(expression);
|
||||
|
||||
// If we parsed MemberExpression and see a `?.` here, then we are part of an optional chain.
|
||||
const isOptionalExpression = parseOptional(SyntaxKind.QuestionDotToken);
|
||||
|
||||
let flags: NodeFlags = NodeFlags.None;
|
||||
if (isOptionalExpression) flags |= NodeFlags.OptionalExpression;
|
||||
if (expression.flags & NodeFlags.Optional) flags |= NodeFlags.OptionalChain;
|
||||
|
||||
let typeArguments: NodeArray<TypeNode>;
|
||||
if (token() === SyntaxKind.LessThanToken) {
|
||||
if (isOptionalExpression) {
|
||||
// If we are part of an optional chain, this *must* be a generic call.
|
||||
typeArguments = parseTypeArgumentsInExpression();
|
||||
}
|
||||
else {
|
||||
// See if this is the start of a generic invocation. If so, consume it and
|
||||
// keep checking for postfix expressions. Otherwise, it's just a '<' that's
|
||||
// part of an arithmetic expression. Break out so we consume it higher in the
|
||||
// stack.
|
||||
typeArguments = tryParse(parseTypeArgumentsInExpression);
|
||||
if (!typeArguments) {
|
||||
return expression;
|
||||
}
|
||||
// See if this is the start of a generic invocation. If so, consume it and
|
||||
// keep checking for postfix expressions. Otherwise, it's just a '<' that's
|
||||
// part of an arithmetic expression. Break out so we consume it higher in the
|
||||
// stack.
|
||||
const typeArguments = tryParse(parseTypeArgumentsInExpression);
|
||||
if (!typeArguments) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
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.LessThanToken) {
|
||||
return expression;
|
||||
else if (token() === SyntaxKind.OpenParenToken) {
|
||||
const callExpr = <CallExpression>createNode(SyntaxKind.CallExpression, expression.pos);
|
||||
callExpr.expression = expression;
|
||||
callExpr.arguments = parseArgumentList();
|
||||
expression = finishNode(callExpr);
|
||||
continue;
|
||||
}
|
||||
|
||||
const callExpr = <CallExpression>createNode(SyntaxKind.CallExpression, expression.pos);
|
||||
callExpr.flags = flags;
|
||||
callExpr.expression = expression;
|
||||
callExpr.typeArguments = typeArguments;
|
||||
callExpr.arguments = parseArgumentList();
|
||||
expression = finishNode(callExpr);
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
|
||||
function parseOptionalExpressionRest(expression: LeftHandSideExpression) {
|
||||
while (token() === SyntaxKind.QuestionDotToken) {
|
||||
const fullStart = getNodePos();
|
||||
nextToken();
|
||||
|
||||
let chain: OptionalChain;
|
||||
while (true) {
|
||||
if (parseOptional(SyntaxKind.OpenBracketToken)) {
|
||||
const elementAccessChain = createNode(SyntaxKind.ElementAccessChain, fullStart) as ElementAccessChain;
|
||||
elementAccessChain.chain = chain;
|
||||
elementAccessChain.argumentExpression = parseExpression();
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
chain = finishNode(elementAccessChain);
|
||||
continue;
|
||||
}
|
||||
else if (token() === SyntaxKind.LessThanToken || token() === SyntaxKind.OpenParenToken) {
|
||||
const callChain = createNode(SyntaxKind.CallChain, fullStart) as CallChain;
|
||||
callChain.chain = chain;
|
||||
callChain.typeArguments = parseTypeArgumentsInExpression();
|
||||
callChain.arguments = parseArgumentList();
|
||||
chain = finishNode(callChain);
|
||||
continue;
|
||||
}
|
||||
else if (!chain || parseOptional(SyntaxKind.DotToken)) {
|
||||
const propertyAccessChain = createNode(SyntaxKind.PropertyAccessChain, fullStart) as PropertyAccessChain;
|
||||
propertyAccessChain.chain = chain;
|
||||
propertyAccessChain.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
|
||||
chain = finishNode(propertyAccessChain);
|
||||
continue;
|
||||
}
|
||||
|
||||
const node = createNode(SyntaxKind.OptionalExpression, expression.pos) as OptionalExpression;
|
||||
node.expression = expression;
|
||||
node.chain = chain;
|
||||
expression = finishNode(node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
function parseArgumentList() {
|
||||
parseExpected(SyntaxKind.OpenParenToken);
|
||||
const result = parseDelimitedList(ParsingContext.ArgumentExpressions, parseArgumentExpression);
|
||||
@@ -4338,7 +4361,6 @@ namespace ts {
|
||||
case SyntaxKind.ColonToken: // foo<x>:
|
||||
case SyntaxKind.SemicolonToken: // foo<x>;
|
||||
case SyntaxKind.QuestionToken: // foo<x>?
|
||||
case SyntaxKind.QuestionDotToken: // foo<x>?.
|
||||
case SyntaxKind.EqualsEqualsToken: // foo<x> ==
|
||||
case SyntaxKind.EqualsEqualsEqualsToken: // foo<x> ===
|
||||
case SyntaxKind.ExclamationEqualsToken: // foo<x> !=
|
||||
|
||||
@@ -105,12 +105,8 @@ namespace ts {
|
||||
return visitParenthesizedExpression(node as ParenthesizedExpression, noDestructuringValue);
|
||||
case SyntaxKind.CatchClause:
|
||||
return visitCatchClause(node as CatchClause);
|
||||
case SyntaxKind.CallExpression:
|
||||
return visitCallExpression(node as CallExpression);
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
return visitPropertyAccessExpression(node as PropertyAccessExpression);
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
return visitElementAccessExpression(node as ElementAccessExpression);
|
||||
case SyntaxKind.OptionalExpression:
|
||||
return visitOptionalExpression(node as OptionalExpression);
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
@@ -726,101 +722,43 @@ namespace ts {
|
||||
return statements;
|
||||
}
|
||||
|
||||
function getEffectiveExpressionOfOptionalExpression(node: PropertyAccessExpression | ElementAccessExpression | CallExpression): Expression | undefined {
|
||||
if (node.flags & NodeFlags.OptionalExpression) {
|
||||
return node.expression;
|
||||
}
|
||||
|
||||
if (node.flags & NodeFlags.OptionalChain) {
|
||||
if (isPropertyAccessExpression(node.expression) ||
|
||||
isElementAccessExpression(node.expression) ||
|
||||
isCallExpression(node.expression)) {
|
||||
return getEffectiveExpressionOfOptionalExpression(node.expression);
|
||||
}
|
||||
function visitOptionalChain(node: OptionalChain | undefined, expression: Expression) {
|
||||
if (!node) return expression;
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.PropertyAccessChain:
|
||||
const propertyAccessExpression = createPropertyAccess(
|
||||
visitOptionalChain(node.chain, expression),
|
||||
visitNode(node.name, visitor, isIdentifier));
|
||||
return propertyAccessExpression;
|
||||
case SyntaxKind.ElementAccessChain:
|
||||
const elementAccessExpression = createElementAccess(
|
||||
visitOptionalChain(node.chain, expression),
|
||||
visitNode(node.argumentExpression, visitor, isExpression));
|
||||
return elementAccessExpression;
|
||||
case SyntaxKind.CallChain:
|
||||
const callExpression = createCall(
|
||||
visitOptionalChain(node.chain, expression),
|
||||
/*typeArguments*/ undefined,
|
||||
visitNodes(node.arguments, visitor, isExpression));
|
||||
return callExpression;
|
||||
}
|
||||
}
|
||||
|
||||
type OptionalChain = PropertyAccessExpression | ElementAccessExpression | CallExpression;
|
||||
|
||||
function isOptionalExpression(node: OptionalChain) {
|
||||
return !!(node.flags & NodeFlags.OptionalExpression);
|
||||
}
|
||||
|
||||
function isOptionalChain(node: Expression): node is OptionalChain {
|
||||
return isPropertyAccessExpression(node)
|
||||
|| isElementAccessExpression(node)
|
||||
|| isCallExpression(node);
|
||||
}
|
||||
|
||||
function visitOptionalChain(node: OptionalChain) {
|
||||
let chain = node;
|
||||
const stack: OptionalChain[] = [chain];
|
||||
while (!isOptionalExpression(chain) && isOptionalChain(chain.expression)) {
|
||||
chain = chain.expression;
|
||||
stack.push(chain);
|
||||
}
|
||||
|
||||
function visitOptionalExpression(node: OptionalExpression) {
|
||||
const root = visitNode(node.expression, visitor, isExpression);
|
||||
const temp = createTempVariable(hoistVariableDeclaration);
|
||||
const root = visitNode(chain.expression, visitor, isExpression);
|
||||
setOriginalNode(temp, root);
|
||||
setSourceMapRange(temp, root);
|
||||
setEmitFlags(temp, EmitFlags.NoComments);
|
||||
|
||||
let expression: LeftHandSideExpression = temp;
|
||||
while (stack.length) {
|
||||
chain = stack.pop();
|
||||
switch (chain.kind) {
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
expression = createPropertyAccess(expression, visitNode(chain.name, visitor, isIdentifier));
|
||||
break;
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
expression = createElementAccess(expression, visitNode(chain.argumentExpression, visitor, isExpression));
|
||||
break;
|
||||
case SyntaxKind.CallExpression:
|
||||
expression = createCall(expression, /*typeArguments*/ undefined, visitNodes(chain.arguments, visitor, isExpression));
|
||||
break;
|
||||
}
|
||||
|
||||
setOriginalNode(expression, chain);
|
||||
setSourceMapRange(expression, chain);
|
||||
setCommentRange(expression, chain);
|
||||
setEmitFlags(expression, EmitFlags.NoLeadingComments);
|
||||
}
|
||||
|
||||
const condition = createEquality(createAssignment(temp, root), createNull());
|
||||
setSourceMapRange(condition, root);
|
||||
|
||||
const voidZero = createVoidZero();
|
||||
setSourceMapRange(voidZero, root);
|
||||
|
||||
const conditional = createConditional(condition, voidZero, expression);
|
||||
setOriginalNode(conditional, node);
|
||||
setSourceMapRange(conditional, node);
|
||||
setCommentRange(conditional, node);
|
||||
// setSourceMapRange(temp, root);
|
||||
const condition = createLogicalOr(
|
||||
createStrictEquality(createAssignment(temp, root), createNull()),
|
||||
createStrictEquality(temp, createVoidZero()));
|
||||
// setSourceMapRange(condition, root);
|
||||
const chain = visitOptionalChain(node.chain, temp);
|
||||
const conditional = createConditional(condition, createVoidZero(), chain);
|
||||
// setSourceMapRange(conditional, node);
|
||||
// setCommentRange(conditional, node);
|
||||
return conditional;
|
||||
}
|
||||
|
||||
function visitPropertyAccessExpression(node: PropertyAccessExpression) {
|
||||
if (node.flags & NodeFlags.Optional) {
|
||||
return visitOptionalChain(node);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitElementAccessExpression(node: ElementAccessExpression) {
|
||||
if (node.flags & NodeFlags.Optional) {
|
||||
return visitOptionalChain(node);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitCallExpression(node: CallExpression) {
|
||||
if (node.flags & NodeFlags.Optional) {
|
||||
return visitOptionalChain(node);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function enableSubstitutionForAsyncMethodsWithSuper() {
|
||||
if ((enabledSubstitutions & ESNextSubstitutionFlags.AsyncMethodsWithSuper) === 0) {
|
||||
enabledSubstitutions |= ESNextSubstitutionFlags.AsyncMethodsWithSuper;
|
||||
|
||||
@@ -513,6 +513,9 @@ namespace ts {
|
||||
// TypeScript namespace or external module import.
|
||||
return visitImportEqualsDeclaration(<ImportEqualsDeclaration>node);
|
||||
|
||||
case SyntaxKind.CallChain:
|
||||
return visitCallChain(<CallChain>node);
|
||||
|
||||
default:
|
||||
Debug.failBadSyntaxKind(node);
|
||||
return visitEachChild(node, visitor, context);
|
||||
@@ -2452,6 +2455,15 @@ namespace ts {
|
||||
return createPartiallyEmittedExpression(expression, node);
|
||||
}
|
||||
|
||||
function visitCallChain(node: CallChain) {
|
||||
return updateCallChain(
|
||||
node,
|
||||
visitNode(node.chain, visitor, isOptionalChain),
|
||||
/*typeArguments*/ undefined,
|
||||
visitNodes(node.arguments, visitor, isExpression)
|
||||
);
|
||||
}
|
||||
|
||||
function visitCallExpression(node: CallExpression) {
|
||||
return updateCall(
|
||||
node,
|
||||
|
||||
+56
-27
@@ -251,6 +251,7 @@ namespace ts {
|
||||
PropertyAccessExpression,
|
||||
ElementAccessExpression,
|
||||
CallExpression,
|
||||
OptionalExpression,
|
||||
NewExpression,
|
||||
TaggedTemplateExpression,
|
||||
TypeAssertionExpression,
|
||||
@@ -275,6 +276,11 @@ namespace ts {
|
||||
NonNullExpression,
|
||||
MetaProperty,
|
||||
|
||||
// Optional chains
|
||||
PropertyAccessChain,
|
||||
ElementAccessChain,
|
||||
CallChain,
|
||||
|
||||
// Misc
|
||||
TemplateSpan,
|
||||
SemicolonClassElement,
|
||||
@@ -383,7 +389,6 @@ namespace ts {
|
||||
CommaListExpression,
|
||||
MergeDeclarationMarker,
|
||||
EndOfDeclarationMarker,
|
||||
OptionalExpression,
|
||||
|
||||
// Enum value count
|
||||
Count,
|
||||
@@ -427,22 +432,20 @@ namespace ts {
|
||||
NestedNamespace = 1 << 2, // Namespace declaration
|
||||
Synthesized = 1 << 3, // Node was synthesized during transformation
|
||||
Namespace = 1 << 4, // Namespace declaration
|
||||
OptionalExpression = 1 << 5, // OptionalExpression (?.)
|
||||
OptionalChain = 1 << 6, // Optional chaining (expressions following ?.)
|
||||
ExportContext = 1 << 7, // Export context (initialized by binding)
|
||||
ContainsThis = 1 << 8, // Interface contains references to "this"
|
||||
HasImplicitReturn = 1 << 9, // If function implicitly returns on one of codepaths (initialized by binding)
|
||||
HasExplicitReturn = 1 << 10, // If function has explicit reachable return on one of codepaths (initialized by binding)
|
||||
GlobalAugmentation = 1 << 11, // Set if module declaration is an augmentation for the global scope
|
||||
HasAsyncFunctions = 1 << 12, // If the file has async functions (initialized by binding)
|
||||
DisallowInContext = 1 << 13, // If node was parsed in a context where 'in-expressions' are not allowed
|
||||
YieldContext = 1 << 14, // If node was parsed in the 'yield' context created when parsing a generator
|
||||
DecoratorContext = 1 << 15, // If node was parsed as part of a decorator
|
||||
AwaitContext = 1 << 16, // If node was parsed in the 'await' context created when parsing an async function
|
||||
ThisNodeHasError = 1 << 17, // If the parser encountered an error when parsing the code that created this node
|
||||
JavaScriptFile = 1 << 18, // If node was parsed in a JavaScript
|
||||
ThisNodeOrAnySubNodesHasError = 1 << 19, // If this node or any of its children had an error
|
||||
HasAggregatedChildData = 1 << 20, // If we've computed data from children and cached it in this node
|
||||
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
|
||||
|
||||
// This flag will be set when the parser encounters a dynamic import expression so that module resolution
|
||||
// will not have to walk the tree if the flag is not set. However, this flag is just a approximation because
|
||||
@@ -453,8 +456,8 @@ namespace ts {
|
||||
// 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 << 20,
|
||||
JSDoc = 1 << 21, // If node was parsed inside jsdoc
|
||||
PossiblyContainsDynamicImport = 1 << 19,
|
||||
JSDoc = 1 << 20, // If node was parsed inside jsdoc
|
||||
|
||||
BlockScoped = Let | Const,
|
||||
|
||||
@@ -462,12 +465,10 @@ namespace ts {
|
||||
ReachabilityAndEmitFlags = ReachabilityCheckFlags | HasAsyncFunctions,
|
||||
|
||||
// Parsing context flags
|
||||
ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile | OptionalChain,
|
||||
ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile,
|
||||
|
||||
// Exclude these flags when parsing a Type
|
||||
TypeExcludesFlags = YieldContext | AwaitContext,
|
||||
|
||||
Optional = OptionalExpression | OptionalChain,
|
||||
}
|
||||
|
||||
export const enum ModifierFlags {
|
||||
@@ -1567,6 +1568,36 @@ namespace ts {
|
||||
expression: ImportExpression;
|
||||
}
|
||||
|
||||
export interface OptionalExpression extends MemberExpression {
|
||||
kind: SyntaxKind.OptionalExpression;
|
||||
expression: LeftHandSideExpression;
|
||||
chain: OptionalChain;
|
||||
}
|
||||
|
||||
export type OptionalChain = PropertyAccessChain | ElementAccessChain | CallChain;
|
||||
|
||||
export interface PropertyAccessChain extends Node {
|
||||
kind: SyntaxKind.PropertyAccessChain;
|
||||
parent?: OptionalChain | OptionalExpression;
|
||||
chain?: OptionalChain;
|
||||
name: Identifier;
|
||||
}
|
||||
|
||||
export interface ElementAccessChain extends Node {
|
||||
kind: SyntaxKind.ElementAccessChain;
|
||||
chain?: OptionalChain;
|
||||
parent?: OptionalChain | OptionalExpression;
|
||||
argumentExpression: Expression;
|
||||
}
|
||||
|
||||
export interface CallChain extends Node {
|
||||
kind: SyntaxKind.CallChain;
|
||||
chain?: OptionalChain;
|
||||
parent?: OptionalChain | OptionalExpression;
|
||||
typeArguments?: NodeArray<TypeNode>;
|
||||
arguments: NodeArray<Expression>;
|
||||
}
|
||||
|
||||
export interface ExpressionWithTypeArguments extends TypeNode {
|
||||
kind: SyntaxKind.ExpressionWithTypeArguments;
|
||||
parent?: HeritageClause;
|
||||
@@ -1587,7 +1618,7 @@ namespace ts {
|
||||
template: TemplateLiteral;
|
||||
}
|
||||
|
||||
export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression | Decorator | JsxOpeningLikeElement;
|
||||
export type CallLikeExpression = CallExpression | CallChain | NewExpression | TaggedTemplateExpression | Decorator | JsxOpeningLikeElement;
|
||||
|
||||
export interface AsExpression extends Expression {
|
||||
kind: SyntaxKind.AsExpression;
|
||||
@@ -3221,18 +3252,16 @@ namespace ts {
|
||||
NonPrimitive = 1 << 24, // intrinsic object type
|
||||
/* @internal */
|
||||
JsxAttributes = 1 << 25, // Jsx attributes type
|
||||
/* @internal */
|
||||
Optional = 1 << 26, // Optional chaining type marker
|
||||
|
||||
Nullable = Undefined | Null,
|
||||
Literal = StringLiteral | NumberLiteral | BooleanLiteral,
|
||||
Unit = Literal | Nullable,
|
||||
StringOrNumberLiteral = StringLiteral | NumberLiteral,
|
||||
/* @internal */
|
||||
DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null | Optional,
|
||||
DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null,
|
||||
PossiblyFalsy = DefinitelyFalsy | String | Number | Boolean,
|
||||
/* @internal */
|
||||
Intrinsic = Any | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive | Optional,
|
||||
Intrinsic = Any | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive,
|
||||
/* @internal */
|
||||
Primitive = String | Number | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null | Literal,
|
||||
StringLike = String | StringLiteral | Index,
|
||||
|
||||
@@ -4464,6 +4464,19 @@ namespace ts {
|
||||
return node.kind === SyntaxKind.MetaProperty;
|
||||
}
|
||||
|
||||
export function isOptionalExpression(node: Node): node is OptionalExpression {
|
||||
return node.kind === SyntaxKind.OptionalExpression;
|
||||
}
|
||||
|
||||
// Optional chains
|
||||
|
||||
export function isOptionalChain(node: Node): node is OptionalChain {
|
||||
const kind = node.kind;
|
||||
return kind === SyntaxKind.PropertyAccessChain
|
||||
|| kind === SyntaxKind.ElementAccessChain
|
||||
|| kind === SyntaxKind.CallChain;
|
||||
}
|
||||
|
||||
// Misc
|
||||
|
||||
export function isTemplateSpan(node: Node): node is TemplateSpan {
|
||||
@@ -5201,6 +5214,7 @@ namespace ts {
|
||||
case SyntaxKind.SuperKeyword:
|
||||
case SyntaxKind.NonNullExpression:
|
||||
case SyntaxKind.MetaProperty:
|
||||
case SyntaxKind.OptionalExpression:
|
||||
case SyntaxKind.ImportKeyword: // technically this is only an Expression if it's in a CallExpression
|
||||
return true;
|
||||
default:
|
||||
|
||||
@@ -446,6 +446,11 @@ namespace ts {
|
||||
visitNode((<ElementAccessExpression>node).expression, visitor, isExpression),
|
||||
visitNode((<ElementAccessExpression>node).argumentExpression, visitor, isExpression));
|
||||
|
||||
case SyntaxKind.OptionalExpression:
|
||||
return updateOptionalExpression(<OptionalExpression>node,
|
||||
visitNode((<OptionalExpression>node).expression, visitor, isExpression),
|
||||
visitNode((<OptionalExpression>node).chain, visitor, isOptionalChain));
|
||||
|
||||
case SyntaxKind.CallExpression:
|
||||
return updateCall(<CallExpression>node,
|
||||
visitNode((<CallExpression>node).expression, visitor, isExpression),
|
||||
@@ -569,6 +574,24 @@ namespace ts {
|
||||
return updateMetaProperty(<MetaProperty>node,
|
||||
visitNode((<MetaProperty>node).name, visitor, isIdentifier));
|
||||
|
||||
// Optional chains
|
||||
|
||||
case SyntaxKind.PropertyAccessChain:
|
||||
return updatePropertyAccessChain(<PropertyAccessChain>node,
|
||||
visitNode((<PropertyAccessChain>node).chain, visitor, isOptionalChain),
|
||||
visitNode((<PropertyAccessChain>node).name, visitor, isIdentifier));
|
||||
|
||||
case SyntaxKind.ElementAccessChain:
|
||||
return updateElementAccessChain(<ElementAccessChain>node,
|
||||
visitNode((<ElementAccessChain>node).chain, visitor, isOptionalChain),
|
||||
visitNode((<ElementAccessChain>node).argumentExpression, visitor, isExpression));
|
||||
|
||||
case SyntaxKind.CallChain:
|
||||
return updateCallChain(<CallChain>node,
|
||||
visitNode((<CallChain>node).chain, visitor, isOptionalChain),
|
||||
nodesVisitor((<CallChain>node).typeArguments, visitor, isTypeNode),
|
||||
nodesVisitor((<CallChain>node).arguments, visitor, isExpression));
|
||||
|
||||
// Misc
|
||||
|
||||
case SyntaxKind.TemplateSpan:
|
||||
@@ -1063,6 +1086,11 @@ namespace ts {
|
||||
result = reduceNode((<ElementAccessExpression>node).argumentExpression, cbNode, result);
|
||||
break;
|
||||
|
||||
case SyntaxKind.OptionalExpression:
|
||||
result = reduceNode((<OptionalExpression>node).expression, cbNode, result);
|
||||
result = reduceNode((<OptionalExpression>node).chain, cbNode, result);
|
||||
break;
|
||||
|
||||
case SyntaxKind.CallExpression:
|
||||
result = reduceNode((<CallExpression>node).expression, cbNode, result);
|
||||
result = reduceNodes((<CallExpression>node).typeArguments, cbNodes, result);
|
||||
@@ -1152,6 +1180,24 @@ namespace ts {
|
||||
result = reduceNode((<AsExpression>node).type, cbNode, result);
|
||||
break;
|
||||
|
||||
// Optional chains
|
||||
|
||||
case SyntaxKind.PropertyAccessChain:
|
||||
result = reduceNode((<PropertyAccessChain>node).chain, cbNode, result);
|
||||
result = reduceNode((<PropertyAccessChain>node).name, cbNode, result);
|
||||
break;
|
||||
|
||||
case SyntaxKind.ElementAccessChain:
|
||||
result = reduceNode((<ElementAccessChain>node).chain, cbNode, result);
|
||||
result = reduceNode((<ElementAccessChain>node).argumentExpression, cbNode, result);
|
||||
break;
|
||||
|
||||
case SyntaxKind.CallChain:
|
||||
result = reduceNode((<CallChain>node).chain, cbNode, result);
|
||||
result = reduceNodes((<CallChain>node).typeArguments, cbNode, result);
|
||||
result = reduceNodes((<CallChain>node).arguments, cbNode, result);
|
||||
break;
|
||||
|
||||
// Misc
|
||||
case SyntaxKind.TemplateSpan:
|
||||
result = reduceNode((<TemplateSpan>node).expression, cbNode, result);
|
||||
|
||||
Reference in New Issue
Block a user