Remove optionality from the initial type of default-valued parameters
When narrowing, remove optionality from the initial type of parameters with initialisers. Note that the type of the initialiser is not used; its presence just means that the initial type of the parameter can't contain undefined. It could contain any other member of a declared union type.
This commit is contained in:
parent
0425175b3a
commit
eaca169b11
|
@ -3368,16 +3368,6 @@ namespace ts {
|
||||||
return strictNullChecks && optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type;
|
return strictNullChecks && optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */
|
|
||||||
function removeOptionalityFromAnnotation(annotatedType: Type, declaration: VariableLikeDeclaration): Type {
|
|
||||||
const annotationIncludesUndefined = strictNullChecks &&
|
|
||||||
declaration.kind === SyntaxKind.Parameter &&
|
|
||||||
declaration.initializer &&
|
|
||||||
getFalsyFlags(annotatedType) & TypeFlags.Undefined &&
|
|
||||||
!(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined);
|
|
||||||
return annotationIncludesUndefined ? getNonNullableType(annotatedType) : annotatedType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the inferred type for a variable, parameter, or property declaration
|
// Return the inferred type for a variable, parameter, or property declaration
|
||||||
function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, includeOptionality: boolean): Type {
|
function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, includeOptionality: boolean): Type {
|
||||||
if (declaration.flags & NodeFlags.JavaScriptFile) {
|
if (declaration.flags & NodeFlags.JavaScriptFile) {
|
||||||
|
@ -3412,7 +3402,7 @@ namespace ts {
|
||||||
|
|
||||||
// Use type from type annotation if one is present
|
// Use type from type annotation if one is present
|
||||||
if (declaration.type) {
|
if (declaration.type) {
|
||||||
const declaredType = removeOptionalityFromAnnotation(getTypeFromTypeNode(declaration.type), declaration);
|
const declaredType = getTypeFromTypeNode(declaration.type);
|
||||||
return addOptionality(declaredType, /*optional*/ declaration.questionToken && includeOptionality);
|
return addOptionality(declaredType, /*optional*/ declaration.questionToken && includeOptionality);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10248,14 +10238,12 @@ namespace ts {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean, flowContainer: Node) {
|
function isFlowNarrowable(reference: Node, type: Type, couldBeUninitialized?: boolean) {
|
||||||
|
return reference.flowNode && (type.flags & TypeFlags.Narrowable || couldBeUninitialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node) {
|
||||||
let key: string;
|
let key: string;
|
||||||
if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) {
|
|
||||||
return declaredType;
|
|
||||||
}
|
|
||||||
const initialType = assumeInitialized ? declaredType :
|
|
||||||
declaredType === autoType || declaredType === autoArrayType ? undefinedType :
|
|
||||||
includeFalsyTypes(declaredType, TypeFlags.Undefined);
|
|
||||||
const visitedFlowStart = visitedFlowCount;
|
const visitedFlowStart = visitedFlowCount;
|
||||||
const evolvedType = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
|
const evolvedType = getTypeFromFlowType(getTypeAtFlowNode(reference.flowNode));
|
||||||
visitedFlowCount = visitedFlowStart;
|
visitedFlowCount = visitedFlowStart;
|
||||||
|
@ -10934,6 +10922,16 @@ namespace ts {
|
||||||
return symbol.flags & SymbolFlags.Variable && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0 && getTypeOfSymbol(symbol) !== autoArrayType;
|
return symbol.flags & SymbolFlags.Variable && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0 && getTypeOfSymbol(symbol) !== autoArrayType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */
|
||||||
|
function removeOptionalityFromDeclaredType(declaredType: Type, declaration: VariableLikeDeclaration): Type {
|
||||||
|
const annotationIncludesUndefined = strictNullChecks &&
|
||||||
|
declaration.kind === SyntaxKind.Parameter &&
|
||||||
|
declaration.initializer &&
|
||||||
|
getFalsyFlags(declaredType) & TypeFlags.Undefined &&
|
||||||
|
!(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined);
|
||||||
|
return annotationIncludesUndefined ? getNonNullableType(declaredType) : declaredType;
|
||||||
|
}
|
||||||
|
|
||||||
function checkIdentifier(node: Identifier): Type {
|
function checkIdentifier(node: Identifier): Type {
|
||||||
const symbol = getResolvedSymbol(node);
|
const symbol = getResolvedSymbol(node);
|
||||||
if (symbol === unknownSymbol) {
|
if (symbol === unknownSymbol) {
|
||||||
|
@ -11052,7 +11050,10 @@ namespace ts {
|
||||||
const assumeInitialized = isParameter || isOuterVariable ||
|
const assumeInitialized = isParameter || isOuterVariable ||
|
||||||
type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isInTypeQuery(node)) ||
|
type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isInTypeQuery(node)) ||
|
||||||
isInAmbientContext(declaration);
|
isInAmbientContext(declaration);
|
||||||
const flowType = getFlowTypeOfReference(node, type, assumeInitialized, flowContainer);
|
const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, getRootDeclaration(declaration) as VariableLikeDeclaration) : type) :
|
||||||
|
type === autoType || type === autoArrayType ? undefinedType :
|
||||||
|
includeFalsyTypes(type, TypeFlags.Undefined);
|
||||||
|
const flowType = isFlowNarrowable(node, type, !assumeInitialized) ? getFlowTypeOfReference(node, type, initialType, flowContainer) : type;
|
||||||
// A variable is considered uninitialized when it is possible to analyze the entire control flow graph
|
// A variable is considered uninitialized when it is possible to analyze the entire control flow graph
|
||||||
// from declaration to use, and when the variable's declared type doesn't include undefined but the
|
// from declaration to use, and when the variable's declared type doesn't include undefined but the
|
||||||
// control flow based type does include undefined.
|
// control flow based type does include undefined.
|
||||||
|
@ -11318,7 +11319,7 @@ namespace ts {
|
||||||
if (isClassLike(container.parent)) {
|
if (isClassLike(container.parent)) {
|
||||||
const symbol = getSymbolOfNode(container.parent);
|
const symbol = getSymbolOfNode(container.parent);
|
||||||
const type = hasModifier(container, ModifierFlags.Static) ? getTypeOfSymbol(symbol) : (<InterfaceType>getDeclaredTypeOfSymbol(symbol)).thisType;
|
const type = hasModifier(container, ModifierFlags.Static) ? getTypeOfSymbol(symbol) : (<InterfaceType>getDeclaredTypeOfSymbol(symbol)).thisType;
|
||||||
return getFlowTypeOfReference(node, type, /*assumeInitialized*/ true, /*flowContainer*/ undefined);
|
return isFlowNarrowable(node, type) ? getFlowTypeOfReference(node, type) : type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInJavaScriptFile(node)) {
|
if (isInJavaScriptFile(node)) {
|
||||||
|
@ -13309,7 +13310,7 @@ namespace ts {
|
||||||
!(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) {
|
!(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) {
|
||||||
return propType;
|
return propType;
|
||||||
}
|
}
|
||||||
const flowType = getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true, /*flowContainer*/ undefined);
|
const flowType = isFlowNarrowable(node, propType) ? getFlowTypeOfReference(node, propType) : propType;
|
||||||
return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType;
|
return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue