@@ -1366,13 +1366,15 @@ const enum IntrinsicTypeKind {
1366
1366
Lowercase,
1367
1367
Capitalize,
1368
1368
Uncapitalize,
1369
+ NoInfer,
1369
1370
}
1370
1371
1371
1372
const intrinsicTypeKinds: ReadonlyMap<string, IntrinsicTypeKind> = new Map(Object.entries({
1372
1373
Uppercase: IntrinsicTypeKind.Uppercase,
1373
1374
Lowercase: IntrinsicTypeKind.Lowercase,
1374
1375
Capitalize: IntrinsicTypeKind.Capitalize,
1375
1376
Uncapitalize: IntrinsicTypeKind.Uncapitalize,
1377
+ NoInfer: IntrinsicTypeKind.NoInfer,
1376
1378
}));
1377
1379
1378
1380
const SymbolLinks = class implements SymbolLinks {
@@ -6749,7 +6751,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
6749
6751
return visitAndTransformType(type, type => conditionalTypeToTypeNode(type as ConditionalType));
6750
6752
}
6751
6753
if (type.flags & TypeFlags.Substitution) {
6752
- return typeToTypeNodeHelper((type as SubstitutionType).baseType, context);
6754
+ const typeNode = typeToTypeNodeHelper((type as SubstitutionType).baseType, context);
6755
+ const noInferSymbol = isNoInferType(type) && getGlobalTypeSymbol("NoInfer" as __String, /*reportErrors*/ false);
6756
+ return noInferSymbol ? symbolToTypeNode(noInferSymbol, context, SymbolFlags.Type, [typeNode]) : typeNode;
6753
6757
}
6754
6758
6755
6759
return Debug.fail("Should be unreachable.");
@@ -15975,8 +15979,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
15975
15979
15976
15980
function getTypeAliasInstantiation(symbol: Symbol, typeArguments: readonly Type[] | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type {
15977
15981
const type = getDeclaredTypeOfSymbol(symbol);
15978
- if (type === intrinsicMarkerType && intrinsicTypeKinds.has(symbol.escapedName as string) && typeArguments && typeArguments.length === 1) {
15979
- return getStringMappingType(symbol, typeArguments[0]);
15982
+ if (type === intrinsicMarkerType) {
15983
+ const typeKind = intrinsicTypeKinds.get(symbol.escapedName as string);
15984
+ if (typeKind !== undefined && typeArguments && typeArguments.length === 1) {
15985
+ return typeKind === IntrinsicTypeKind.NoInfer ? getNoInferType(typeArguments[0]) : getStringMappingType(symbol, typeArguments[0]);
15986
+ }
15980
15987
}
15981
15988
const links = getSymbolLinks(symbol);
15982
15989
const typeParameters = links.typeParameters!;
@@ -16158,10 +16165,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16158
16165
return links.resolvedJSDocType;
16159
16166
}
16160
16167
16168
+ function getNoInferType(type: Type) {
16169
+ return isNoInferTargetType(type) ? getOrCreateSubstitutionType(type, unknownType) : type;
16170
+ }
16171
+
16172
+ function isNoInferTargetType(type: Type): boolean {
16173
+ // This is effectively a more conservative and predictable form of couldContainTypeVariables. We want to
16174
+ // preserve NoInfer<T> only for types that could contain type variables, but we don't want to exhaustively
16175
+ // examine all object type members.
16176
+ return !!(type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, isNoInferTargetType) ||
16177
+ type.flags & TypeFlags.Substitution && !isNoInferType(type) && isNoInferTargetType((type as SubstitutionType).baseType) ||
16178
+ type.flags & TypeFlags.Object && !isEmptyAnonymousObjectType(type) ||
16179
+ type.flags & (TypeFlags.Instantiable & ~TypeFlags.Substitution) && !isPatternLiteralType(type));
16180
+ }
16181
+
16182
+ function isNoInferType(type: Type) {
16183
+ // A NoInfer<T> type is represented as a substitution type with a TypeFlags.Unknown constraint.
16184
+ return !!(type.flags & TypeFlags.Substitution && (type as SubstitutionType).constraint.flags & TypeFlags.Unknown);
16185
+ }
16186
+
16161
16187
function getSubstitutionType(baseType: Type, constraint: Type) {
16162
- if (constraint.flags & TypeFlags.AnyOrUnknown || constraint === baseType || baseType.flags & TypeFlags.Any) {
16163
- return baseType;
16164
- }
16188
+ return constraint.flags & TypeFlags.AnyOrUnknown || constraint === baseType || baseType.flags & TypeFlags.Any ?
16189
+ baseType :
16190
+ getOrCreateSubstitutionType(baseType, constraint);
16191
+ }
16192
+
16193
+ function getOrCreateSubstitutionType(baseType: Type, constraint: Type) {
16165
16194
const id = `${getTypeId(baseType)}>${getTypeId(constraint)}`;
16166
16195
const cached = substitutionTypes.get(id);
16167
16196
if (cached) {
@@ -16175,7 +16204,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16175
16204
}
16176
16205
16177
16206
function getSubstitutionIntersection(substitutionType: SubstitutionType) {
16178
- return getIntersectionType([substitutionType.constraint, substitutionType.baseType]);
16207
+ return isNoInferType(substitutionType) ? substitutionType.baseType : getIntersectionType([substitutionType.constraint, substitutionType.baseType]);
16179
16208
}
16180
16209
16181
16210
function isUnaryTupleTypeNode(node: TypeNode) {
@@ -17853,7 +17882,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
17853
17882
17854
17883
function getIndexType(type: Type, indexFlags = defaultIndexFlags): Type {
17855
17884
type = getReducedType(type);
17856
- return shouldDeferIndexType(type, indexFlags) ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, indexFlags) :
17885
+ return isNoInferType(type) ? getNoInferType(getIndexType((type as SubstitutionType).baseType, indexFlags)) :
17886
+ shouldDeferIndexType(type, indexFlags) ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, indexFlags) :
17857
17887
type.flags & TypeFlags.Union ? getIntersectionType(map((type as UnionType).types, t => getIndexType(t, indexFlags))) :
17858
17888
type.flags & TypeFlags.Intersection ? getUnionType(map((type as IntersectionType).types, t => getIndexType(t, indexFlags))) :
17859
17889
getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(type as MappedType, indexFlags) :
@@ -19941,6 +19971,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
19941
19971
}
19942
19972
if (flags & TypeFlags.Substitution) {
19943
19973
const newBaseType = instantiateType((type as SubstitutionType).baseType, mapper);
19974
+ if (isNoInferType(type)) {
19975
+ return getNoInferType(newBaseType);
19976
+ }
19944
19977
const newConstraint = instantiateType((type as SubstitutionType).constraint, mapper);
19945
19978
// A substitution type originates in the true branch of a conditional type and can be resolved
19946
19979
// to just the base type in the same cases as the conditional type resolves to its true branch
@@ -25459,7 +25492,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
25459
25492
inferFromTypes(originalSource, originalTarget);
25460
25493
25461
25494
function inferFromTypes(source: Type, target: Type): void {
25462
- if (!couldContainTypeVariables(target)) {
25495
+ if (!couldContainTypeVariables(target) || isNoInferType(target) ) {
25463
25496
return;
25464
25497
}
25465
25498
if (source === wildcardType || source === blockedStringType) {
@@ -25532,6 +25565,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
25532
25565
}
25533
25566
}
25534
25567
if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) {
25568
+ if (isNoInferType(target)) {
25569
+ return;
25570
+ }
25535
25571
target = getActualTypeVariable(target);
25536
25572
}
25537
25573
if (target.flags & TypeFlags.TypeVariable) {
0 commit comments