@@ -1940,7 +1940,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1940
1940
const markerSubTypeForCheck = createTypeParameter();
1941
1941
markerSubTypeForCheck.constraint = markerSuperTypeForCheck;
1942
1942
1943
- const noTypePredicate = createTypePredicate(TypePredicateKind.Identifier, "<<unresolved>>", 0, anyType);
1943
+ const noTypePredicate = createTypePredicate(TypePredicateKind.Identifier, "<<unresolved>>", 0, anyType, /*strictSubtype*/ false );
1944
1944
1945
1945
const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None);
1946
1946
const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, errorType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None);
@@ -7156,7 +7156,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
7156
7156
setEmitFlags(factory.createIdentifier(typePredicate.parameterName), EmitFlags.NoAsciiEscaping) :
7157
7157
factory.createThisTypeNode();
7158
7158
const typeNode = typePredicate.type && typeToTypeNodeHelper(typePredicate.type, context);
7159
- returnTypeNode = factory.createTypePredicateNode(assertsModifier, parameterName, typeNode);
7159
+ const subtypeOfModifier = typePredicate.oneSided ? factory.createToken(SyntaxKind.SubtypeOfKeyword) : undefined;
7160
+ returnTypeNode = factory.createTypePredicateNode(assertsModifier, parameterName, typeNode, subtypeOfModifier);
7160
7161
}
7161
7162
else {
7162
7163
const returnType = getReturnTypeOfSignature(signature);
@@ -9528,7 +9529,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
9528
9529
const predicate = factory.createTypePredicateNode(
9529
9530
typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? factory.createToken(SyntaxKind.AssertsKeyword) : undefined,
9530
9531
typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? factory.createIdentifier(typePredicate.parameterName) : factory.createThisTypeNode(),
9531
- typePredicate.type && nodeBuilder.typeToTypeNode(typePredicate.type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName)! // TODO: GH#18217
9532
+ typePredicate.type && nodeBuilder.typeToTypeNode(typePredicate.type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName)!, // TODO: GH#18217
9533
+ typePredicate.oneSided ? factory.createToken(SyntaxKind.SubtypeOfKeyword) : undefined
9532
9534
);
9533
9535
const printer = createPrinter({ removeComments: true });
9534
9536
const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration);
@@ -14083,8 +14085,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
14083
14085
return isPropertyDeclaration(node) && !hasAccessorModifier(node) && node.questionToken;
14084
14086
}
14085
14087
14086
- function createTypePredicate(kind: TypePredicateKind, parameterName: string | undefined, parameterIndex: number | undefined, type: Type | undefined): TypePredicate {
14087
- return { kind, parameterName, parameterIndex, type } as TypePredicate;
14088
+ function createTypePredicate(kind: TypePredicateKind, parameterName: string | undefined, parameterIndex: number | undefined, type: Type | undefined, oneSided: boolean ): TypePredicate {
14089
+ return { kind, parameterName, parameterIndex, type, oneSided } as TypePredicate;
14088
14090
}
14089
14091
14090
14092
/**
@@ -14408,9 +14410,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
14408
14410
const parameterName = node.parameterName;
14409
14411
const type = node.type && getTypeFromTypeNode(node.type);
14410
14412
return parameterName.kind === SyntaxKind.ThisType ?
14411
- createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsThis : TypePredicateKind.This, /*parameterName*/ undefined, /*parameterIndex*/ undefined, type) :
14413
+ createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsThis : TypePredicateKind.This, /*parameterName*/ undefined, /*parameterIndex*/ undefined, type, !!node.subtypeOfModifier ) :
14412
14414
createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsIdentifier : TypePredicateKind.Identifier, parameterName.escapedText as string,
14413
- findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), type);
14415
+ findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), type, !!node.subtypeOfModifier );
14414
14416
}
14415
14417
14416
14418
function getUnionOrIntersectionType(types: Type[], kind: TypeFlags | undefined, unionReduction?: UnionReduction) {
@@ -16075,6 +16077,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16075
16077
function getUnionOrIntersectionTypePredicate(signatures: readonly Signature[], kind: TypeFlags | undefined): TypePredicate | undefined {
16076
16078
let first: TypePredicate | undefined;
16077
16079
const types: Type[] = [];
16080
+ let oneSided!: boolean;
16078
16081
for (const sig of signatures) {
16079
16082
const pred = getTypePredicateOfSignature(sig);
16080
16083
if (!pred || pred.kind === TypePredicateKind.AssertsThis || pred.kind === TypePredicateKind.AssertsIdentifier) {
@@ -16091,9 +16094,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16091
16094
// No common type predicate.
16092
16095
return undefined;
16093
16096
}
16097
+ oneSided = kind === TypeFlags.Intersection ? oneSided || pred.oneSided : oneSided && pred.oneSided;
16094
16098
}
16095
16099
else {
16096
16100
first = pred;
16101
+ oneSided = pred.oneSided;
16097
16102
}
16098
16103
types.push(pred.type);
16099
16104
}
@@ -16102,7 +16107,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16102
16107
return undefined;
16103
16108
}
16104
16109
const compositeType = getUnionOrIntersectionType(types, kind);
16105
- return createTypePredicate(first.kind, first.parameterName, first.parameterIndex, compositeType);
16110
+ return createTypePredicate(first.kind, first.parameterName, first.parameterIndex, compositeType, oneSided );
16106
16111
}
16107
16112
16108
16113
function typePredicateKindsMatch(a: TypePredicate, b: TypePredicate): boolean {
@@ -18259,7 +18264,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
18259
18264
}
18260
18265
18261
18266
function instantiateTypePredicate(predicate: TypePredicate, mapper: TypeMapper): TypePredicate {
18262
- return createTypePredicate(predicate.kind, predicate.parameterName, predicate.parameterIndex, instantiateType(predicate.type, mapper));
18267
+ return createTypePredicate(predicate.kind, predicate.parameterName, predicate.parameterIndex, instantiateType(predicate.type, mapper), predicate.oneSided );
18263
18268
}
18264
18269
18265
18270
function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature {
@@ -19588,7 +19593,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
19588
19593
}
19589
19594
}
19590
19595
19591
- const related = source.type === target.type ? Ternary.True :
19596
+ const related = !source.oneSided && target.oneSided ? Ternary.False :
19597
+ source.type === target.type ? Ternary.True :
19592
19598
source.type && target.type ? compareTypes(source.type, target.type, reportErrors) :
19593
19599
Ternary.False;
19594
19600
if (related === Ternary.False && reportErrors) {
@@ -22630,6 +22636,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22630
22636
22631
22637
function compareTypePredicatesIdentical(source: TypePredicate | undefined, target: TypePredicate | undefined, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
22632
22638
return !(source && target && typePredicateKindsMatch(source, target)) ? Ternary.False :
22639
+ source.oneSided !== target.oneSided ? Ternary.False :
22633
22640
source.type === target.type ? Ternary.True :
22634
22641
source.type && target.type ? compareTypes(source.type, target.type) :
22635
22642
Ternary.False;
@@ -26890,15 +26897,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
26890
26897
return getNarrowedType(type, targetType, assumeTrue, /*checkDerived*/ true);
26891
26898
}
26892
26899
26893
- function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) {
26894
- const key = type.flags & TypeFlags.Union ? `N${getTypeId(type)},${getTypeId(candidate)},${(assumeTrue ? 1 : 0) | (checkDerived ? 2 : 0)}` : undefined;
26895
- return getCachedType(key) ?? setCachedType(key, getNarrowedTypeWorker(type, candidate, assumeTrue, checkDerived));
26900
+ function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean, oneSided?: boolean ) {
26901
+ const key = type.flags & TypeFlags.Union ? `N${getTypeId(type)},${getTypeId(candidate)},${(assumeTrue ? 1 : 0) | (checkDerived ? 2 : 0) | (oneSided ? 4 : 0) }` : undefined;
26902
+ return getCachedType(key) ?? setCachedType(key, getNarrowedTypeWorker(type, candidate, assumeTrue, checkDerived, oneSided ));
26896
26903
}
26897
26904
26898
- function getNarrowedTypeWorker(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) {
26905
+ function getNarrowedTypeWorker(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean, oneSided?: boolean ) {
26899
26906
const isRelated = checkDerived ? isTypeDerivedFrom : isTypeSubtypeOf;
26900
26907
if (!assumeTrue) {
26901
- return filterType(type, t => !isRelated(t, candidate));
26908
+ return oneSided ? type : filterType(type, t => !isRelated(t, candidate));
26902
26909
}
26903
26910
if (type.flags & TypeFlags.AnyOrUnknown) {
26904
26911
return candidate;
@@ -26959,15 +26966,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
26959
26966
const predicateArgument = getTypePredicateArgument(predicate, callExpression);
26960
26967
if (predicateArgument) {
26961
26968
if (isMatchingReference(reference, predicateArgument)) {
26962
- return getNarrowedType(type, predicate.type, assumeTrue, /*checkDerived*/ false);
26969
+ return getNarrowedType(type, predicate.type, assumeTrue, /*checkDerived*/ false, predicate.oneSided );
26963
26970
}
26964
26971
if (strictNullChecks && assumeTrue && optionalChainContainsReference(predicateArgument, reference) &&
26965
26972
!(getTypeFacts(predicate.type) & TypeFacts.EQUndefined)) {
26966
26973
type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull);
26967
26974
}
26968
26975
const access = getDiscriminantPropertyAccess(predicateArgument, type);
26969
26976
if (access) {
26970
- return narrowTypeByDiscriminant(type, access, t => getNarrowedType(t, predicate.type!, assumeTrue, /*checkDerived*/ false));
26977
+ return narrowTypeByDiscriminant(type, access, t => getNarrowedType(t, predicate.type!, assumeTrue, /*checkDerived*/ false, predicate.oneSided ));
26971
26978
}
26972
26979
}
26973
26980
}
0 commit comments