Destructuring declaration prefers type annotation type (#25282)

* Destructuring declaration prefers type annotation type

Previously, getTypeForBindingElement would always union the declarations type and
the type of the default initializer. Now, if the declaration has a type
annotation, it does not union with the initializer type. The type
annotation's type is the one used.

* Small cleanup in parentDeclarationHasTypeAnnotation

* Refactoring based on PR comments

* Combine getCombined*Flags into a single helper function

Retain the individual functions since they are used a lot.

* Remove unneeded temp
This commit is contained in:
Nathan Shively-Sanders
2018-06-28 10:41:38 -07:00
committed by GitHub
parent 950593b669
commit 5c2eeb20b1
17 changed files with 328 additions and 55 deletions

View File

@@ -4161,7 +4161,7 @@ namespace ts {
}
const parent = getDeclarationContainer(node);
// If the node is not exported or it is not ambient module element (except import declaration)
if (!(getCombinedModifierFlags(node) & ModifierFlags.Export) &&
if (!(getCombinedModifierFlags(node as Declaration) & ModifierFlags.Export) &&
!(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && parent.flags & NodeFlags.Ambient)) {
return isGlobalSourceFile(parent);
}
@@ -4525,7 +4525,7 @@ namespace ts {
if (strictNullChecks && declaration.initializer && !(getFalsyFlags(checkExpressionCached(declaration.initializer)) & TypeFlags.Undefined)) {
type = getTypeWithFacts(type, TypeFacts.NEUndefined);
}
return declaration.initializer ?
return declaration.initializer && !getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration)) ?
getUnionType([type, checkExpressionCached(declaration.initializer)], UnionReduction.Subtype) :
type;
}
@@ -22096,7 +22096,7 @@ namespace ts {
return hasModifier(node, ModifierFlags.Private) && !!(node.flags & NodeFlags.Ambient);
}
function getEffectiveDeclarationFlags(n: Node, flagsToCheck: ModifierFlags): ModifierFlags {
function getEffectiveDeclarationFlags(n: Declaration, flagsToCheck: ModifierFlags): ModifierFlags {
let flags = getCombinedModifierFlags(n);
// children of classes (even ambient classes) should not be marked as ambient or export

View File

@@ -903,7 +903,7 @@ namespace ts {
export function isConst(node: Node): boolean {
return !!(getCombinedNodeFlags(node) & NodeFlags.Const)
|| !!(getCombinedModifierFlags(node) & ModifierFlags.Const);
|| !!(isDeclaration(node) && getCombinedModifierFlags(node) & ModifierFlags.Const);
}
export function isLet(node: Node): boolean {
@@ -4605,33 +4605,36 @@ namespace ts {
return isEmptyBindingPattern(node.name);
}
function walkUpBindingElementsAndPatterns(node: Node): Node {
while (node && (node.kind === SyntaxKind.BindingElement || isBindingPattern(node))) {
node = node.parent;
export function walkUpBindingElementsAndPatterns(binding: BindingElement): VariableDeclaration | ParameterDeclaration {
let node = binding.parent;
while (isBindingElement(node.parent)) {
node = node.parent.parent;
}
return node;
return node.parent;
}
export function getCombinedModifierFlags(node: Node): ModifierFlags {
node = walkUpBindingElementsAndPatterns(node);
let flags = getModifierFlags(node);
function getCombinedFlags(node: Node, getFlags: (n: Node) => number): number {
if (isBindingElement(node)) {
node = walkUpBindingElementsAndPatterns(node);
}
let flags = getFlags(node);
if (node.kind === SyntaxKind.VariableDeclaration) {
node = node.parent;
}
if (node && node.kind === SyntaxKind.VariableDeclarationList) {
flags |= getModifierFlags(node);
flags |= getFlags(node);
node = node.parent;
}
if (node && node.kind === SyntaxKind.VariableStatement) {
flags |= getModifierFlags(node);
flags |= getFlags(node);
}
return flags;
}
export function getCombinedModifierFlags(node: Declaration): ModifierFlags {
return getCombinedFlags(node, getModifierFlags);
}
// Returns the node flags for this node and all relevant parent nodes. This is done so that
// nodes like variable declarations and binding elements can returned a view of their flags
// that includes the modifiers from their container. i.e. flags like export/declare aren't
@@ -4640,23 +4643,7 @@ namespace ts {
// list. By calling this function, all those flags are combined so that the client can treat
// the node as if it actually had those flags.
export function getCombinedNodeFlags(node: Node): NodeFlags {
node = walkUpBindingElementsAndPatterns(node);
let flags = node.flags;
if (node.kind === SyntaxKind.VariableDeclaration) {
node = node.parent;
}
if (node && node.kind === SyntaxKind.VariableDeclarationList) {
flags |= node.flags;
node = node.parent;
}
if (node && node.kind === SyntaxKind.VariableStatement) {
flags |= node.flags;
}
return flags;
return getCombinedFlags(node, n => n.flags);
}
/**

View File

@@ -1044,7 +1044,7 @@ namespace ts {
}
export function getNodeModifiers(node: Node): string {
const flags = getCombinedModifierFlags(node);
const flags = isDeclaration(node) ? getCombinedModifierFlags(node) : ModifierFlags.None;
const result: string[] = [];
if (flags & ModifierFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier);