mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-27 22:39:59 -05:00
Change narrowing rules for parameter initialisers
They don't narrow the parameter type, except to remove undefined, and only if the initialiser type doesn't include undefined.
This commit is contained in:
@@ -810,7 +810,7 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement | ParameterDeclaration): FlowNode {
|
||||
function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode {
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowAssignment>{
|
||||
flags: FlowFlags.Assignment,
|
||||
@@ -819,6 +819,15 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
function createFlowInitializedParameter(antecedent: FlowNode, node: ParameterDeclaration): FlowNode {
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowInitializedParameter>{
|
||||
flags: FlowFlags.InitializedParameter,
|
||||
antecedent,
|
||||
node
|
||||
};
|
||||
}
|
||||
|
||||
function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode {
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowArrayMutation>{
|
||||
@@ -2312,7 +2321,7 @@ namespace ts {
|
||||
else {
|
||||
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes);
|
||||
if (node.initializer) {
|
||||
currentFlow = createFlowAssignment(currentFlow, node);
|
||||
currentFlow = createFlowInitializedParameter(currentFlow, node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9060,8 +9060,8 @@ namespace ts {
|
||||
switch (source.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
return target.kind === SyntaxKind.Identifier && getResolvedSymbol(<Identifier>source) === getResolvedSymbol(<Identifier>target) ||
|
||||
(target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement) && getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(<Identifier>source)) === getSymbolOfNode(target) ||
|
||||
target.kind === SyntaxKind.Parameter && getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source as Identifier)) === getSymbolOfNode(target);
|
||||
(target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement || target.kind === SyntaxKind.Parameter) &&
|
||||
getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source as Identifier)) === getSymbolOfNode(target);
|
||||
case SyntaxKind.ThisKeyword:
|
||||
return target.kind === SyntaxKind.ThisKeyword;
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
@@ -9155,6 +9155,13 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getInitializedParameterReducedType(declaredType: UnionType, assignedType: Type) {
|
||||
if (declaredType === assignedType || getFalsyFlags(assignedType) & TypeFlags.Undefined) {
|
||||
return declaredType;
|
||||
}
|
||||
return getTypeWithFacts(declaredType, TypeFacts.NEUndefined);
|
||||
}
|
||||
|
||||
// Remove those constituent types of declaredType to which no constituent type of assignedType is assignable.
|
||||
// For example, when a variable of type number | string | boolean is assigned a value of type number | boolean,
|
||||
// we remove type string.
|
||||
@@ -9351,7 +9358,7 @@ namespace ts {
|
||||
getInitialTypeOfBindingElement(<BindingElement>node);
|
||||
}
|
||||
|
||||
function getInitialOrAssignedType(node: VariableDeclaration | BindingElement | Expression) {
|
||||
function getInitialOrAssignedType(node: VariableDeclaration | BindingElement | Expression | ParameterDeclaration) {
|
||||
return node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement || node.kind === SyntaxKind.Parameter ?
|
||||
getInitialType(<VariableDeclaration | BindingElement | ParameterDeclaration>node) :
|
||||
getAssignedType(<Expression>node);
|
||||
@@ -9622,6 +9629,13 @@ namespace ts {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (flow.flags & FlowFlags.InitializedParameter) {
|
||||
type = getTypeAtFlowInitializedParameter(flow as FlowInitializedParameter);
|
||||
if (!type) {
|
||||
flow = (flow as FlowInitializedParameter).antecedent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (flow.flags & FlowFlags.Condition) {
|
||||
type = getTypeAtFlowCondition(<FlowCondition>flow);
|
||||
}
|
||||
@@ -9669,6 +9683,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeAtFlowInitializedParameter(flow: FlowInitializedParameter) {
|
||||
const node = flow.node;
|
||||
// Parameter initializers don't really narrow the declared type except to remove undefined.
|
||||
// If the initializer includes undefined in the type, it doesn't even remove undefined.
|
||||
if (isMatchingReference(reference, node)) {
|
||||
if (declaredType.flags & TypeFlags.Union) {
|
||||
return getInitializedParameterReducedType(<UnionType>declaredType, getInitialOrAssignedType(node));
|
||||
}
|
||||
return declaredType;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getTypeAtFlowAssignment(flow: FlowAssignment) {
|
||||
const node = flow.node;
|
||||
// Assignments only narrow the computed type if the declared type is a union type. Thus, we
|
||||
|
||||
@@ -2042,12 +2042,13 @@ namespace ts {
|
||||
BranchLabel = 1 << 2, // Non-looping junction
|
||||
LoopLabel = 1 << 3, // Looping junction
|
||||
Assignment = 1 << 4, // Assignment
|
||||
TrueCondition = 1 << 5, // Condition known to be true
|
||||
FalseCondition = 1 << 6, // Condition known to be false
|
||||
SwitchClause = 1 << 7, // Switch statement clause
|
||||
ArrayMutation = 1 << 8, // Potential array mutation
|
||||
Referenced = 1 << 9, // Referenced as antecedent once
|
||||
Shared = 1 << 10, // Referenced as antecedent more than once
|
||||
InitializedParameter = 1 << 5, // Parameter with initializer
|
||||
TrueCondition = 1 << 6, // Condition known to be true
|
||||
FalseCondition = 1 << 7, // Condition known to be false
|
||||
SwitchClause = 1 << 8, // Switch statement clause
|
||||
ArrayMutation = 1 << 9, // Potential array mutation
|
||||
Referenced = 1 << 10, // Referenced as antecedent once
|
||||
Shared = 1 << 11, // Referenced as antecedent more than once
|
||||
Label = BranchLabel | LoopLabel,
|
||||
Condition = TrueCondition | FalseCondition
|
||||
}
|
||||
@@ -2097,6 +2098,11 @@ namespace ts {
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
export interface FlowInitializedParameter extends FlowNode {
|
||||
node: ParameterDeclaration;
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
export type FlowType = Type | IncompleteType;
|
||||
|
||||
// Incomplete types occur during control flow analysis of loops. An IncompleteType
|
||||
|
||||
Reference in New Issue
Block a user