@@ -16925,10 +16925,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
16925
16925
}
16926
16926
16927
16927
function removeStringLiteralsMatchedByTemplateLiterals(types: Type[]) {
16928
- const templates = filter(types, t =>
16929
- !!(t.flags & TypeFlags.TemplateLiteral) &&
16930
- isPatternLiteralType(t) &&
16931
- (t as TemplateLiteralType).types.every(t => !(t.flags & TypeFlags.Intersection) || !areIntersectedTypesAvoidingPrimitiveReduction((t as IntersectionType).types))) as TemplateLiteralType[];
16928
+ const templates = filter(types, t => !!(t.flags & TypeFlags.TemplateLiteral) && isPatternLiteralType(t)) as TemplateLiteralType[];
16932
16929
if (templates.length) {
16933
16930
let i = types.length;
16934
16931
while (i > 0) {
@@ -17439,20 +17436,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
17439
17436
return reduceLeft(types, (n, t) => n + getConstituentCount(t), 0);
17440
17437
}
17441
17438
17442
- function areIntersectedTypesAvoidingPrimitiveReduction(types: Type[], primitiveFlags = TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt): boolean {
17443
- if (types.length !== 2) {
17444
- return false;
17445
- }
17446
- const [t1, t2] = types;
17447
- return !!(t1.flags & primitiveFlags) && t2 === emptyTypeLiteralType || !!(t2.flags & primitiveFlags) && t1 === emptyTypeLiteralType;
17448
- }
17449
-
17450
17439
function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type {
17451
17440
const links = getNodeLinks(node);
17452
17441
if (!links.resolvedType) {
17453
17442
const aliasSymbol = getAliasSymbolForTypeNode(node);
17454
17443
const types = map(node.types, getTypeFromTypeNode);
17455
- const noSupertypeReduction = areIntersectedTypesAvoidingPrimitiveReduction(types);
17444
+ // We perform no supertype reduction for X & {} or {} & X, where X is one of string, number, bigint,
17445
+ // or a pattern literal template type. This enables union types like "a" | "b" | string & {} or
17446
+ // "aa" | "ab" | `a${string}` which preserve the literal types for purposes of statement completion.
17447
+ const emptyIndex = types.length === 2 ? types.indexOf(emptyTypeLiteralType) : -1;
17448
+ const t = emptyIndex >= 0 ? types[1 - emptyIndex] : unknownType;
17449
+ const noSupertypeReduction = !!(t.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt) || t.flags & TypeFlags.TemplateLiteral && isPatternLiteralType(t));
17456
17450
links.resolvedType = getIntersectionType(types, aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol), noSupertypeReduction);
17457
17451
}
17458
17452
return links.resolvedType;
@@ -17735,7 +17729,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
17735
17729
17736
17730
function createTemplateLiteralType(texts: readonly string[], types: readonly Type[]) {
17737
17731
const type = createType(TypeFlags.TemplateLiteral) as TemplateLiteralType;
17738
- type.objectFlags = getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable);
17739
17732
type.texts = texts;
17740
17733
type.types = types;
17741
17734
return type;
@@ -18060,12 +18053,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
18060
18053
18061
18054
function isPatternLiteralPlaceholderType(type: Type): boolean {
18062
18055
if (type.flags & TypeFlags.Intersection) {
18063
- return !isGenericType(type) && some((type as IntersectionType).types, t => !!(t.flags & (TypeFlags.Literal | TypeFlags.Nullable)) || isPatternLiteralPlaceholderType(t));
18056
+ // Return true if the intersection consists of one or more placeholders and zero or
18057
+ // more object type tags.
18058
+ let seenPlaceholder = false;
18059
+ for (const t of (type as IntersectionType).types) {
18060
+ if (t.flags & (TypeFlags.Literal | TypeFlags.Nullable) || isPatternLiteralPlaceholderType(t)) {
18061
+ seenPlaceholder = true;
18062
+ }
18063
+ else if (!(t.flags & TypeFlags.Object)) {
18064
+ return false;
18065
+ }
18066
+ }
18067
+ return seenPlaceholder;
18064
18068
}
18065
18069
return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || isPatternLiteralType(type);
18066
18070
}
18067
18071
18068
18072
function isPatternLiteralType(type: Type) {
18073
+ // A pattern literal type is a template literal or a string mapping type that contains only
18074
+ // non-generic pattern literal placeholders.
18069
18075
return !!(type.flags & TypeFlags.TemplateLiteral) && every((type as TemplateLiteralType).types, isPatternLiteralPlaceholderType) ||
18070
18076
!!(type.flags & TypeFlags.StringMapping) && isPatternLiteralPlaceholderType((type as StringMappingType).type);
18071
18077
}
@@ -18083,12 +18089,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
18083
18089
}
18084
18090
18085
18091
function getGenericObjectFlags(type: Type): ObjectFlags {
18086
- if (type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral )) {
18087
- if (!((type as UnionOrIntersectionType | TemplateLiteralType ).objectFlags & ObjectFlags.IsGenericTypeComputed)) {
18088
- (type as UnionOrIntersectionType | TemplateLiteralType ).objectFlags |= ObjectFlags.IsGenericTypeComputed |
18089
- reduceLeft((type as UnionOrIntersectionType | TemplateLiteralType ).types, (flags, t) => flags | getGenericObjectFlags(t), 0);
18092
+ if (type.flags & (TypeFlags.UnionOrIntersection)) {
18093
+ if (!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) {
18094
+ (type as UnionOrIntersectionType).objectFlags |= ObjectFlags.IsGenericTypeComputed |
18095
+ reduceLeft((type as UnionOrIntersectionType).types, (flags, t) => flags | getGenericObjectFlags(t), 0);
18090
18096
}
18091
- return (type as UnionOrIntersectionType | TemplateLiteralType ).objectFlags & ObjectFlags.IsGenericType;
18097
+ return (type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericType;
18092
18098
}
18093
18099
if (type.flags & TypeFlags.Substitution) {
18094
18100
if (!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) {
@@ -18098,7 +18104,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
18098
18104
return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType;
18099
18105
}
18100
18106
return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) |
18101
- (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0);
18107
+ (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags. StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0);
18102
18108
}
18103
18109
18104
18110
function getSimplifiedType(type: Type, writing: boolean): Type {
@@ -24768,7 +24774,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
24768
24774
objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ||
24769
24775
objectFlags & (ObjectFlags.Mapped | ObjectFlags.ReverseMapped | ObjectFlags.ObjectRestType | ObjectFlags.InstantiationExpressionType)
24770
24776
) ||
24771
- type.flags & ( TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((type as UnionOrIntersectionType | TemplateLiteralType ).types, couldContainTypeVariables));
24777
+ type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((type as UnionOrIntersectionType).types, couldContainTypeVariables));
24772
24778
if (type.flags & TypeFlags.ObjectFlagsType) {
24773
24779
(type as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (result ? ObjectFlags.CouldContainTypeVariables : 0);
24774
24780
}
0 commit comments