mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'suggested-changes-57465' into infer-type-predicate-16069
This commit is contained in:
@@ -1094,7 +1094,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
|
||||
inAssignmentPattern = saveInAssignmentPattern;
|
||||
return;
|
||||
}
|
||||
if (node.kind >= SyntaxKind.FirstStatement && node.kind <= SyntaxKind.LastStatement && !options.allowUnreachableCode) {
|
||||
if (node.kind >= SyntaxKind.FirstStatement && node.kind <= SyntaxKind.LastStatement && (!options.allowUnreachableCode || node.kind === SyntaxKind.ReturnStatement)) {
|
||||
(node as HasFlowNode).flowNode = currentFlow;
|
||||
}
|
||||
switch (node.kind) {
|
||||
|
||||
+8
-20
@@ -15463,7 +15463,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
createTypePredicateFromTypePredicateNode(type, signature) :
|
||||
jsdocPredicate || noTypePredicate;
|
||||
}
|
||||
else if (signature.declaration && isFunctionLikeDeclaration(signature.declaration) && (!signature.resolvedReturnType || signature.resolvedReturnType === booleanType)) {
|
||||
else if (signature.declaration && isFunctionLikeDeclaration(signature.declaration) && (!signature.resolvedReturnType || signature.resolvedReturnType.flags & TypeFlags.Boolean)) {
|
||||
const { declaration } = signature;
|
||||
signature.resolvedTypePredicate = noTypePredicate; // avoid infinite loop
|
||||
signature.resolvedTypePredicate = getTypePredicateFromBody(declaration) || noTypePredicate;
|
||||
@@ -37411,7 +37411,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
// Only attempt to infer a type predicate if there's exactly one return.
|
||||
let singleReturn: Expression | undefined;
|
||||
let singleReturnStatement: ReturnStatement | undefined;
|
||||
if (func.body && func.body.kind !== SyntaxKind.Block) {
|
||||
singleReturn = func.body; // arrow function
|
||||
}
|
||||
@@ -37420,7 +37419,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
const bailedEarly = forEachReturnStatement(func.body as Block, returnStatement => {
|
||||
if (singleReturn || !returnStatement.expression) return true;
|
||||
singleReturnStatement = returnStatement;
|
||||
singleReturn = returnStatement.expression;
|
||||
});
|
||||
if (bailedEarly || !singleReturn) return undefined;
|
||||
@@ -37439,11 +37437,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
function checkIfExpressionRefinesAnyParameter(expr: Expression): [number, Type] | undefined {
|
||||
expr = skipParentheses(expr, /*excludeJSDocTypeAssertions*/ true);
|
||||
const type = checkExpressionCached(expr);
|
||||
if (type !== booleanType) return undefined;
|
||||
if (!(type.flags & TypeFlags.Boolean)) return undefined;
|
||||
|
||||
return forEach(func.parameters, (param, i) => {
|
||||
const initType = getSymbolLinks(param.symbol).type;
|
||||
if (!initType || initType === booleanType || isSymbolAssigned(param.symbol)) {
|
||||
const initType = getTypeOfSymbol(param.symbol);
|
||||
if (!initType || initType.flags & TypeFlags.Boolean || isSymbolAssigned(param.symbol)) {
|
||||
// Refining "x: boolean" to "x is true" or "x is false" isn't useful.
|
||||
return;
|
||||
}
|
||||
@@ -37455,7 +37453,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function checkIfExpressionRefinesParameter(expr: Expression, param: ParameterDeclaration, initType: Type): Type | undefined {
|
||||
const antecedent = (expr as Expression & { flowNode?: FlowNode; }).flowNode ?? { flags: FlowFlags.Start };
|
||||
const antecedent = (expr as Expression & { flowNode?: FlowNode; }).flowNode ||
|
||||
expr.parent.kind === SyntaxKind.ReturnStatement && (expr.parent as ReturnStatement).flowNode ||
|
||||
{ flags: FlowFlags.Start };
|
||||
const trueCondition: FlowCondition = {
|
||||
flags: FlowFlags.TrueCondition,
|
||||
node: expr,
|
||||
@@ -37472,19 +37472,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
flags: FlowFlags.FalseCondition,
|
||||
};
|
||||
const falseSubtype = getFlowTypeOfReference(param.name, trueType, trueType, func, falseCondition);
|
||||
if (!isTypeIdenticalTo(falseSubtype, neverType)) return undefined;
|
||||
|
||||
// the parameter type may already have been narrowed due to an assertion.
|
||||
// There's no precise way to represent an assertion that's also a predicate. Best not to try.
|
||||
// We do this check last since it's unlikely to filter out many possible predicates.
|
||||
if (singleReturnStatement?.flowNode) {
|
||||
const typeAtReturn = getFlowTypeOfReference(param.name, initType, initType, func, singleReturnStatement?.flowNode);
|
||||
if (typeAtReturn !== initType) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return trueType;
|
||||
return falseSubtype.flags & TypeFlags.Never ? trueType : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,11 +14,9 @@ inferTypePredicates.ts(113,7): error TS2322: Type 'string | number' is not assig
|
||||
inferTypePredicates.ts(115,7): error TS2322: Type 'string | number' is not assignable to type 'number'.
|
||||
Type 'string' is not assignable to type 'number'.
|
||||
inferTypePredicates.ts(205,7): error TS2741: Property 'z' is missing in type 'C1' but required in type 'C2'.
|
||||
inferTypePredicates.ts(252,7): error TS2322: Type 'string | number | Date' is not assignable to type 'string'.
|
||||
Type 'number' is not assignable to type 'string'.
|
||||
|
||||
|
||||
==== inferTypePredicates.ts (11 errors) ====
|
||||
==== inferTypePredicates.ts (10 errors) ====
|
||||
// https://github.com/microsoft/TypeScript/issues/16069
|
||||
|
||||
const numsOrNull = [1, 2, 3, 4, null];
|
||||
@@ -298,9 +296,6 @@ inferTypePredicates.ts(252,7): error TS2322: Type 'string | number | Date' is no
|
||||
declare let snd: string | number | Date;
|
||||
if (assertAndPredicate(snd)) {
|
||||
let t: string = snd; // should error
|
||||
~
|
||||
!!! error TS2322: Type 'string | number | Date' is not assignable to type 'string'.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
}
|
||||
|
||||
function isNumberWithThis(this: Date, x: number | string) {
|
||||
|
||||
@@ -886,7 +886,7 @@ if (isNumOrStr(unk)) {
|
||||
|
||||
// A function can be a type predicate even if it throws.
|
||||
function assertAndPredicate(x: string | number | Date) {
|
||||
>assertAndPredicate : (x: string | number | Date) => boolean
|
||||
>assertAndPredicate : (x: string | number | Date) => x is string
|
||||
>x : string | number | Date
|
||||
|
||||
if (x instanceof Date) {
|
||||
@@ -910,12 +910,12 @@ declare let snd: string | number | Date;
|
||||
|
||||
if (assertAndPredicate(snd)) {
|
||||
>assertAndPredicate(snd) : boolean
|
||||
>assertAndPredicate : (x: string | number | Date) => boolean
|
||||
>assertAndPredicate : (x: string | number | Date) => x is string
|
||||
>snd : string | number | Date
|
||||
|
||||
let t: string = snd; // should error
|
||||
>t : string
|
||||
>snd : string | number | Date
|
||||
>snd : string
|
||||
}
|
||||
|
||||
function isNumberWithThis(this: Date, x: number | string) {
|
||||
|
||||
Reference in New Issue
Block a user