diff --git a/package-lock.json b/package-lock.json index d829cabf8c4..57b28dc8df3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -234,7 +234,7 @@ "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" @@ -638,9 +638,9 @@ "dev": true }, "@types/node": { - "version": "17.0.35", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz", - "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==", + "version": "17.0.38", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.38.tgz", + "integrity": "sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==", "dev": true }, "@types/node-fetch": { @@ -1964,7 +1964,7 @@ "detect-newline": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==", "dev": true }, "diff": { @@ -2600,7 +2600,7 @@ "event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", "dev": true, "requires": { "d": "1", @@ -3130,7 +3130,7 @@ "get-func-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", "dev": true }, "get-intrinsic": { @@ -3390,7 +3390,7 @@ "gulp-concat": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", - "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", + "integrity": "sha512-a2scActrQrDBpBbR3WUZGyGS1JEPLg5PZJdIa7/Bi3GuKAmPYDK6SFhy/NZq5R8KsKKFvtfR0fakbUCcKGCCjg==", "dev": true, "requires": { "concat-with-sourcemaps": "^1.0.0", @@ -3401,7 +3401,7 @@ "gulp-insert": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/gulp-insert/-/gulp-insert-0.5.0.tgz", - "integrity": "sha1-MjE/E+SiPPWsylzl8MCAkjx3hgI=", + "integrity": "sha512-SDKCWmjomAo0N0Bzj9qEKIfURORJR/72p6AbDBIK9yKZw794ROTrQHliBem+NJzS2GsTWSm8dGWJ5L7KtjnMRA==", "dev": true, "requires": { "readable-stream": "^1.0.26-4", @@ -3411,7 +3411,7 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "readable-stream": { @@ -4006,7 +4006,7 @@ "kew": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", - "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "integrity": "sha512-IG6nm0+QtAMdXt9KvbgbGdvY50RSrw+U4sGZg+KlrSKPJEwVE5JVoI3d7RWfSMdBQneRheeAOj3lIjX5VL/9RQ==", "dev": true }, "kind-of": { @@ -4138,7 +4138,7 @@ "lru-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", "dev": true, "requires": { "es5-ext": "~0.10.2" @@ -4705,7 +4705,7 @@ "mocha-fivemat-progress-reporter": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/mocha-fivemat-progress-reporter/-/mocha-fivemat-progress-reporter-0.1.0.tgz", - "integrity": "sha1-zK/w4ckc9Vf+d+B535lUuRt0d1Y=", + "integrity": "sha512-nCf6dmCEHObJ8BBrcjW+UHYvVtHEL+FliYR/Mfc/v7dKenNmBQ0ZSuvlICgsyQy9Tt581ldvh+SReS4qp4LrQw==", "dev": true }, "ms": { @@ -4834,7 +4834,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true }, "object-copy": { @@ -5192,7 +5192,7 @@ "extend-shallow": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", + "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==", "dev": true, "requires": { "kind-of": "^1.1.0" @@ -5201,7 +5201,7 @@ "kind-of": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", + "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==", "dev": true } } @@ -5960,7 +5960,7 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "readable-stream": { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a921bcd3ec0..8188e14f5c8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -74,7 +74,7 @@ namespace ts { TypeofNEString = 1 << 8, // typeof x !== "string" TypeofNENumber = 1 << 9, // typeof x !== "number" TypeofNEBigInt = 1 << 10, // typeof x !== "bigint" - TypeofNEBoolean = 1 << 11, // typeof x !== "boolean" + TypeofNEBoolean = 1 << 11, // typeof x !== "boolean" TypeofNESymbol = 1 << 12, // typeof x !== "symbol" TypeofNEObject = 1 << 13, // typeof x !== "object" TypeofNEFunction = 1 << 14, // typeof x !== "function" @@ -87,7 +87,10 @@ namespace ts { NEUndefinedOrNull = 1 << 21, // x != undefined / x != null Truthy = 1 << 22, // x Falsy = 1 << 23, // !x - All = (1 << 24) - 1, + IsUndefined = 1 << 24, // Exactly undefined + IsNull = 1 << 25, // Exactly null + IsUndefinedOrNull = IsUndefined | IsNull, + All = (1 << 27) - 1, // The following members encode facts about particular kinds of types for use in the getTypeFacts function. // The presence of a particular fact means that the given test is true for some (and possibly all) values // of that kind of type. @@ -129,11 +132,13 @@ namespace ts { ObjectFacts = ObjectStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy, FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy, - UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy, - NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy, - EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull), + VoidFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy, + UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy | IsUndefined, + NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy | IsNull, + EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull | IsUndefinedOrNull), + EmptyObjectFacts = All & ~IsUndefinedOrNull, + UnknownFacts = All & ~IsUndefinedOrNull, AllTypeofNE = TypeofNEString | TypeofNENumber | TypeofNEBigInt | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | NEUndefined, - EmptyObjectFacts = All, // Masks OrFactsMask = TypeofEQFunction | TypeofNEObject, AndFactsMask = All & ~OrFactsMask, @@ -848,6 +853,8 @@ namespace ts { emptyTypeLiteralSymbol.members = createSymbolTable(); const emptyTypeLiteralType = createAnonymousType(emptyTypeLiteralSymbol, emptySymbols, emptyArray, emptyArray, emptyArray); + const unknownUnionType = strictNullChecks ? getUnionType([undefinedType, nullType, createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray)]) : unknownType; + const emptyGenericType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray) as ObjectType as GenericType; emptyGenericType.instantiations = new Map(); @@ -2476,7 +2483,12 @@ namespace ts { function checkAndReportErrorForUsingTypeAsValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { if (meaning & (SymbolFlags.Value & ~SymbolFlags.NamespaceModule)) { if (isPrimitiveTypeName(name)) { - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, unescapeLeadingUnderscores(name)); + if (isExtendedByInterface(errorLocation)) { + error(errorLocation, Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_an_interface_can_only_extend_named_types_and_classes, unescapeLeadingUnderscores(name)); + } + else { + error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, unescapeLeadingUnderscores(name)); + } return true; } const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~SymbolFlags.Value, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false)); @@ -2497,6 +2509,17 @@ namespace ts { return false; } + function isExtendedByInterface(node: Node): boolean { + const grandparent = node.parent.parent; + const parentOfGrandparent = grandparent.parent; + if(grandparent && parentOfGrandparent){ + const isExtending = isHeritageClause(grandparent) && grandparent.token === SyntaxKind.ExtendsKeyword; + const isInterface = isInterfaceDeclaration(parentOfGrandparent); + return isExtending && isInterface; + } + return false; + } + function maybeMappedType(node: Node, symbol: Symbol) { const container = findAncestor(node.parent, n => isComputedPropertyName(n) || isPropertySignature(n) ? false : isTypeLiteralNode(n) || "quit") as TypeLiteralNode | undefined; @@ -5620,7 +5643,7 @@ namespace ts { anyType : getNonMissingTypeOfSymbol(propertySymbol); const saveEnclosingDeclaration = context.enclosingDeclaration; context.enclosingDeclaration = undefined; - if (context.tracker.trackSymbol && getCheckFlags(propertySymbol) & CheckFlags.Late && isLateBoundName(propertySymbol.escapedName)) { + if (context.tracker.trackSymbol && isLateBoundName(propertySymbol.escapedName)) { if (propertySymbol.declarations) { const decl = first(propertySymbol.declarations); if (hasLateBindableName(decl)) { @@ -7556,7 +7579,7 @@ namespace ts { ...!length(baseTypes) ? [] : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))], ...!length(implementsExpressions) ? [] : [factory.createHeritageClause(SyntaxKind.ImplementsKeyword, implementsExpressions)] ]; - const symbolProps = getNonInterhitedProperties(classType, baseTypes, getPropertiesOfType(classType)); + const symbolProps = getNonInheritedProperties(classType, baseTypes, getPropertiesOfType(classType)); const publicSymbolProps = filter(symbolProps, s => { // `valueDeclaration` could be undefined if inherited from // a union/intersection base type, but inherited properties @@ -8885,7 +8908,7 @@ namespace ts { if (getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration))) { // In strict null checking mode, if a default value of a non-undefined type is specified, remove // undefined from the final type. - return strictNullChecks && !(getFalsyFlags(checkDeclarationInitializer(declaration, CheckMode.Normal)) & TypeFlags.Undefined) ? getNonUndefinedType(type) : type; + return strictNullChecks && !(getTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal)) & TypeFacts.IsUndefined) ? getNonUndefinedType(type) : type; } return widenTypeInferredFromInitializer(declaration, getUnionType([getNonUndefinedType(type), checkDeclarationInitializer(declaration, CheckMode.Normal)], UnionReduction.Subtype)); } @@ -12058,7 +12081,7 @@ namespace ts { } } } - else if (t.flags & TypeFlags.DisjointDomains) { + else if (t.flags & TypeFlags.DisjointDomains || isEmptyAnonymousObjectType(t)) { hasDisjointDomainType = true; } } @@ -12069,7 +12092,7 @@ namespace ts { // We add any types belong to one of the disjoint domains because they might cause the final // intersection operation to reduce the union constraints. for (const t of types) { - if (t.flags & TypeFlags.DisjointDomains) { + if (t.flags & TypeFlags.DisjointDomains || isEmptyAnonymousObjectType(t)) { constraints = append(constraints, t); } } @@ -12285,7 +12308,7 @@ namespace ts { let objectType; return !!(type.flags & TypeFlags.IndexedAccess && getObjectFlags(objectType = (type as IndexedAccessType).objectType) & ObjectFlags.Mapped && !isGenericMappedType(objectType) && isGenericIndexType((type as IndexedAccessType).indexType) && - !(objectType as MappedType).declaration.questionToken && !(objectType as MappedType).declaration.nameType); + !(getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.ExcludeOptional) && !(objectType as MappedType).declaration.nameType); } /** @@ -14826,7 +14849,7 @@ namespace ts { return includes; } - function removeRedundantPrimitiveTypes(types: Type[], includes: TypeFlags) { + function removeRedundantSupertypes(types: Type[], includes: TypeFlags) { let i = types.length; while (i > 0) { i--; @@ -14835,7 +14858,9 @@ namespace ts { t.flags & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || t.flags & TypeFlags.Number && includes & TypeFlags.NumberLiteral || t.flags & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral || - t.flags & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol; + t.flags & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol || + t.flags & TypeFlags.Void && includes & TypeFlags.Undefined || + isEmptyAnonymousObjectType(t) && includes & TypeFlags.DefinitelyNonNullable; if (remove) { orderedRemoveItemAt(types, i); } @@ -14959,7 +14984,7 @@ namespace ts { // a type alias of the form "type List = T & { next: List }" cannot be reduced during its declaration. // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution // for intersections of types with signatures can be deterministic. - function getIntersectionType(types: readonly Type[], aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function getIntersectionType(types: readonly Type[], aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], noSupertypeReduction?: boolean): Type { const typeMembershipMap: ESMap = new Map(); const includes = addTypesToIntersection(typeMembershipMap, 0, types); const typeSet: Type[] = arrayFrom(typeMembershipMap.values()); @@ -14996,11 +15021,10 @@ namespace ts { if (includes & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral || includes & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral || - includes & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol) { - removeRedundantPrimitiveTypes(typeSet, includes); - } - if (includes & TypeFlags.IncludesEmptyObject && includes & TypeFlags.Object) { - orderedRemoveItemAt(typeSet, findIndex(typeSet, isEmptyAnonymousObjectType)); + includes & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol || + includes & TypeFlags.Void && includes & TypeFlags.Undefined || + includes & TypeFlags.IncludesEmptyObject && includes & TypeFlags.DefinitelyNonNullable) { + if (!noSupertypeReduction) removeRedundantSupertypes(typeSet, includes); } if (includes & TypeFlags.IncludesMissingType) { typeSet[typeSet.indexOf(undefinedType)] = missingType; @@ -15039,8 +15063,9 @@ namespace ts { } const constituents = getCrossProductIntersections(typeSet); // We attach a denormalized origin type when at least one constituent of the cross-product union is an - // intersection (i.e. when the intersection didn't just reduce one or more unions to smaller unions). - const origin = some(constituents, t => !!(t.flags & TypeFlags.Intersection)) ? createOriginUnionOrIntersectionType(TypeFlags.Intersection, typeSet) : undefined; + // intersection (i.e. when the intersection didn't just reduce one or more unions to smaller unions) and + // the denormalized origin has fewer constituents than the union itself. + const origin = some(constituents, t => !!(t.flags & TypeFlags.Intersection)) && getConstituentCountOfTypes(constituents) > getConstituentCountOfTypes(typeSet) ? createOriginUnionOrIntersectionType(TypeFlags.Intersection, typeSet) : undefined; result = getUnionType(constituents, UnionReduction.Literal, aliasSymbol, aliasTypeArguments, origin); } } @@ -15086,12 +15111,23 @@ namespace ts { return intersections; } + function getConstituentCount(type: Type): number { + return !(type.flags & TypeFlags.UnionOrIntersection) || type.aliasSymbol ? 1 : + type.flags & TypeFlags.Union && (type as UnionType).origin ? getConstituentCount((type as UnionType).origin!) : + getConstituentCountOfTypes((type as UnionOrIntersectionType).types); + } + + function getConstituentCountOfTypes(types: Type[]): number { + return reduceLeft(types, (n, t) => n + getConstituentCount(t), 0); + } + function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { const aliasSymbol = getAliasSymbolForTypeNode(node); - links.resolvedType = getIntersectionType(map(node.types, getTypeFromTypeNode), - aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol)); + const types = map(node.types, getTypeFromTypeNode); + const noSupertypeReduction = types.length === 2 && !!(types[0].flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) && types[1] === emptyTypeLiteralType; + links.resolvedType = getIntersectionType(types, aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol), noSupertypeReduction); } return links.resolvedType; } @@ -17981,7 +18017,7 @@ namespace ts { const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(sourceType)); const targetSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(targetType)); const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) && - (getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable); + (getTypeFacts(sourceType) & TypeFacts.IsUndefinedOrNull) === (getTypeFacts(targetType) & TypeFacts.IsUndefinedOrNull); let related = callbacks ? compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) : !(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors); @@ -18116,6 +18152,18 @@ namespace ts { type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral && getMembersOfSymbol(type.symbol).size === 0)); } + function isUnknownLikeUnionType(type: Type) { + if (strictNullChecks && type.flags & TypeFlags.Union) { + if (!((type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnionComputed)) { + const types = (type as UnionType).types; + (type as UnionType).objectFlags |= ObjectFlags.IsUnknownLikeUnionComputed | (types.length >= 3 && types[0].flags & TypeFlags.Undefined && + types[1].flags & TypeFlags.Null && some(types, isEmptyAnonymousObjectType) ? ObjectFlags.IsUnknownLikeUnion : 0); + } + return !!((type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnion); + } + return false; + } + function isStringIndexSignatureOnlyType(type: Type): boolean { return type.flags & TypeFlags.Object && !isGenericMappedType(type) && getPropertiesOfType(type).length === 0 && getIndexInfosOfType(type).length === 1 && !!getIndexInfoOfType(type, stringType) || type.flags & TypeFlags.UnionOrIntersection && every((type as UnionOrIntersectionType).types, isStringIndexSignatureOnlyType) || @@ -18183,7 +18231,7 @@ namespace ts { // Since unions and intersections may reduce to `never`, we exclude them here. if (s & TypeFlags.Undefined && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & (TypeFlags.Undefined | TypeFlags.Void))) return true; if (s & TypeFlags.Null && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & TypeFlags.Null)) return true; - if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive) return true; + if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive && !(relation === strictSubtypeRelation && isEmptyAnonymousObjectType(source))) return true; if (relation === assignableRelation || relation === comparableRelation) { if (s & TypeFlags.Any) return true; // Type number or any numeric literal type is assignable to any numeric enum type or any @@ -18191,6 +18239,8 @@ namespace ts { // bit-flag enum types sometimes look like literal enum types with numeric literal values. if (s & (TypeFlags.Number | TypeFlags.NumberLiteral) && !(s & TypeFlags.EnumLiteral) && ( t & TypeFlags.Enum || relation === assignableRelation && t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral)) return true; + // Anything is assignable to a union containing undefined, null, and {} + if (isUnknownLikeUnionType(target)) return true; } return false; } @@ -18233,16 +18283,28 @@ namespace ts { function getNormalizedType(type: Type, writing: boolean): Type { while (true) { - let t = isFreshLiteralType(type) ? (type as FreshableType).regularType : - getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).node ? createTypeReference((type as TypeReference).target, getTypeArguments(type as TypeReference)) : - type.flags & TypeFlags.UnionOrIntersection ? getReducedType(type) : + const t = isFreshLiteralType(type) ? (type as FreshableType).regularType : + getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).node ? createTypeReference((type as TypeReference).target, getTypeArguments(type as TypeReference)) : getSingleBaseForNonAugmentingSubtype(type) || type : + type.flags & TypeFlags.UnionOrIntersection ? getNormalizedUnionOrIntersectionType(type as UnionOrIntersectionType, writing) : type.flags & TypeFlags.Substitution ? writing ? (type as SubstitutionType).baseType : (type as SubstitutionType).substitute : type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) : type; - t = getSingleBaseForNonAugmentingSubtype(t) || t; - if (t === type) break; + if (t === type) return t; type = t; } + } + + function getNormalizedUnionOrIntersectionType(type: UnionOrIntersectionType, writing: boolean) { + const reduced = getReducedType(type); + if (reduced !== type) { + return reduced; + } + if (type.flags & TypeFlags.Intersection) { + const normalizedTypes = sameMap(type.types, t => getNormalizedType(t, writing)); + if (normalizedTypes !== type.types) { + return getIntersectionType(normalizedTypes); + } + } return type; } @@ -18772,6 +18834,9 @@ namespace ts { return; } reportRelationError(headMessage, source, target); + if (strictNullChecks && source.flags & TypeFlags.TypeVariable && source.symbol?.declarations?.[0] && !getConstraintOfType(source as TypeVariable) && isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) { + associateRelatedInfo(createDiagnosticForNode(source.symbol.declarations[0], Diagnostics.This_type_parameter_probably_needs_an_extends_object_constraint)); + } } function traceUnionsOrIntersectionsTooLarge(source: Type, target: Type): void { @@ -19576,13 +19641,6 @@ namespace ts { // IndexedAccess comparisons are handled above in the `targetFlags & TypeFlage.IndexedAccess` branch if (!(sourceFlags & TypeFlags.IndexedAccess && targetFlags & TypeFlags.IndexedAccess)) { const constraint = getConstraintOfType(source as TypeVariable) || unknownType; - if (!getConstraintOfType(source as TypeVariable) || (sourceFlags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) { - // A type variable with no constraint is not related to the non-primitive object type. - if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive), RecursionFlags.Both)) { - resetErrorInfo(saveErrorInfo); - return result; - } - } // hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) { resetErrorInfo(saveErrorInfo); @@ -21106,9 +21164,11 @@ namespace ts { return getSupertypeOrUnion(types); } const primaryTypes = filter(types, t => !(t.flags & TypeFlags.Nullable)); - return primaryTypes.length ? - getNullableType(getSupertypeOrUnion(primaryTypes), getFalsyFlagsOfTypes(types) & TypeFlags.Nullable) : - getUnionType(types, UnionReduction.Subtype); + if (primaryTypes.length) { + const supertypeOrUnion = getSupertypeOrUnion(primaryTypes); + return primaryTypes === types ? supertypeOrUnion : getUnionType([supertypeOrUnion, ...filter(types, t => !!(t.flags & TypeFlags.Nullable))]); + } + return getUnionType(types, UnionReduction.Subtype); } // Return the leftmost type for which no type to the right is a subtype. @@ -21325,30 +21385,8 @@ namespace ts { return value.base10Value === "0"; } - function getFalsyFlagsOfTypes(types: Type[]): TypeFlags { - let result: TypeFlags = 0; - for (const t of types) { - result |= getFalsyFlags(t); - } - return result; - } - - // Returns the String, Number, Boolean, StringLiteral, NumberLiteral, BooleanLiteral, Void, Undefined, or Null - // flags for the string, number, boolean, "", 0, false, void, undefined, or null types respectively. Returns - // no flags for all other types (including non-falsy literal types). - function getFalsyFlags(type: Type): TypeFlags { - return type.flags & TypeFlags.Union ? getFalsyFlagsOfTypes((type as UnionType).types) : - type.flags & TypeFlags.StringLiteral ? (type as StringLiteralType).value === "" ? TypeFlags.StringLiteral : 0 : - type.flags & TypeFlags.NumberLiteral ? (type as NumberLiteralType).value === 0 ? TypeFlags.NumberLiteral : 0 : - type.flags & TypeFlags.BigIntLiteral ? isZeroBigInt(type as BigIntLiteralType) ? TypeFlags.BigIntLiteral : 0 : - type.flags & TypeFlags.BooleanLiteral ? (type === falseType || type === regularFalseType) ? TypeFlags.BooleanLiteral : 0 : - type.flags & TypeFlags.PossiblyFalsy; - } - function removeDefinitelyFalsyTypes(type: Type): Type { - return getFalsyFlags(type) & TypeFlags.DefinitelyFalsy ? - filterType(type, t => !(getFalsyFlags(t) & TypeFlags.DefinitelyFalsy)) : - type; + return filterType(type, t => !!(getTypeFacts(t) & TypeFacts.Truthy)); } function extractDefinitelyFalsyTypes(type: Type): Type { @@ -21387,21 +21425,16 @@ namespace ts { } function getGlobalNonNullableTypeInstantiation(type: Type) { - // First reduce away any constituents that are assignable to 'undefined' or 'null'. This not only eliminates - // 'undefined' and 'null', but also higher-order types such as a type parameter 'U extends undefined | null' - // that isn't eliminated by a NonNullable instantiation. - const reducedType = getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); if (!deferredGlobalNonNullableTypeAlias) { deferredGlobalNonNullableTypeAlias = getGlobalSymbol("NonNullable" as __String, SymbolFlags.TypeAlias, /*diagnostic*/ undefined) || unknownSymbol; } - // If the NonNullable type is available, return an instantiation. Otherwise just return the reduced type. return deferredGlobalNonNullableTypeAlias !== unknownSymbol ? - getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [reducedType]) : - reducedType; + getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]) : + getIntersectionType([type, emptyObjectType]); } function getNonNullableType(type: Type): Type { - return strictNullChecks ? getGlobalNonNullableTypeInstantiation(type) : type; + return strictNullChecks ? getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; } function addOptionalTypeMarker(type: Type) { @@ -22112,13 +22145,40 @@ namespace ts { sourceEnd.slice(sourceEnd.length - endLen) !== targetEnd.slice(targetEnd.length - endLen); } - function isValidBigIntString(s: string): boolean { + /** + * Tests whether the provided string can be parsed as a number. + * @param s The string to test. + * @param roundTripOnly Indicates the resulting number matches the input when converted back to a string. + */ + function isValidNumberString(s: string, roundTripOnly: boolean): boolean { + if (s === "") return false; + const n = +s; + return isFinite(n) && (!roundTripOnly || "" + n === s); + } + + /** + * @param text a valid bigint string excluding a trailing `n`, but including a possible prefix `-`. Use `isValidBigIntString(text, roundTripOnly)` before calling this function. + */ + function parseBigIntLiteralType(text: string) { + const negative = text.startsWith("-"); + const base10Value = parsePseudoBigInt(`${negative ? text.slice(1) : text}n`); + return getBigIntLiteralType({ negative, base10Value }); + } + + /** + * Tests whether the provided string can be parsed as a bigint. + * @param s The string to test. + * @param roundTripOnly Indicates the resulting bigint matches the input when converted back to a string. + */ + function isValidBigIntString(s: string, roundTripOnly: boolean): boolean { + if (s === "") return false; const scanner = createScanner(ScriptTarget.ESNext, /*skipTrivia*/ false); let success = true; scanner.setOnError(() => success = false); scanner.setText(s + "n"); let result = scanner.scan(); - if (result === SyntaxKind.MinusToken) { + const negative = result === SyntaxKind.MinusToken; + if (negative) { result = scanner.scan(); } const flags = scanner.getTokenFlags(); @@ -22127,7 +22187,8 @@ namespace ts { // * a bigint can be scanned, and that when it is scanned, it is // * the full length of the input string (so the scanner is one character beyond the augmented input length) // * it does not contain a numeric seperator (the `BigInt` constructor does not accept a numeric seperator in its input) - return success && result === SyntaxKind.BigIntLiteral && scanner.getTextPos() === (s.length + 1) && !(flags & TokenFlags.ContainsSeparator); + return success && result === SyntaxKind.BigIntLiteral && scanner.getTextPos() === (s.length + 1) && !(flags & TokenFlags.ContainsSeparator) + && (!roundTripOnly || s === pseudoBigIntToString({ negative, base10Value: parsePseudoBigInt(scanner.getTokenValue()) })); } function isValidTypeForTemplateLiteralPlaceholder(source: Type, target: Type): boolean { @@ -22136,8 +22197,8 @@ namespace ts { } if (source.flags & TypeFlags.StringLiteral) { const value = (source as StringLiteralType).value; - return !!(target.flags & TypeFlags.Number && value !== "" && isFinite(+value) || - target.flags & TypeFlags.BigInt && value !== "" && isValidBigIntString(value) || + return !!(target.flags & TypeFlags.Number && isValidNumberString(value, /*roundTripOnly*/ false) || + target.flags & TypeFlags.BigInt && isValidBigIntString(value, /*roundTripOnly*/ false) || target.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) && value === (target as IntrinsicType).intrinsicName); } if (source.flags & TypeFlags.TemplateLiteral) { @@ -22715,7 +22776,60 @@ namespace ts { // succeed. That would be a pointless and confusing outcome. if (matches || every(target.texts, s => s.length === 0)) { for (let i = 0; i < types.length; i++) { - inferFromTypes(matches ? matches[i] : neverType, types[i]); + const source = matches ? matches[i] : neverType; + const target = types[i]; + + // If we are inferring from a string literal type to a type variable whose constraint includes one of the + // allowed template literal placeholder types, infer from a literal type corresponding to the constraint. + if (source.flags & TypeFlags.StringLiteral && target.flags & TypeFlags.TypeVariable) { + const inferenceContext = getInferenceInfoForType(target); + const constraint = inferenceContext ? getBaseConstraintOfType(inferenceContext.typeParameter) : undefined; + if (constraint && !isTypeAny(constraint)) { + const constraintTypes = constraint.flags & TypeFlags.Union ? (constraint as UnionType).types : [constraint]; + let allTypeFlags: TypeFlags = reduceLeft(constraintTypes, (flags, t) => flags | t.flags, 0 as TypeFlags); + + // If the constraint contains `string`, we don't need to look for a more preferred type + if (!(allTypeFlags & TypeFlags.String)) { + const str = (source as StringLiteralType).value; + + // If the type contains `number` or a number literal and the string isn't a valid number, exclude numbers + if (allTypeFlags & TypeFlags.NumberLike && !isValidNumberString(str, /*roundTripOnly*/ true)) { + allTypeFlags &= ~TypeFlags.NumberLike; + } + + // If the type contains `bigint` or a bigint literal and the string isn't a valid bigint, exclude bigints + if (allTypeFlags & TypeFlags.BigIntLike && !isValidBigIntString(str, /*roundTripOnly*/ true)) { + allTypeFlags &= ~TypeFlags.BigIntLike; + } + + // for each type in the constraint, find the highest priority matching type + const matchingType = reduceLeft(constraintTypes, (left, right) => + !(right.flags & allTypeFlags) ? left : + left.flags & TypeFlags.String ? left : right.flags & TypeFlags.String ? source : + left.flags & TypeFlags.TemplateLiteral ? left : right.flags & TypeFlags.TemplateLiteral && isTypeMatchedByTemplateLiteralType(source, right as TemplateLiteralType) ? source : + left.flags & TypeFlags.StringMapping ? left : right.flags & TypeFlags.StringMapping && str === applyStringMapping(right.symbol, str) ? source : + left.flags & TypeFlags.StringLiteral ? left : right.flags & TypeFlags.StringLiteral && (right as StringLiteralType).value === str ? right : + left.flags & TypeFlags.Number ? left : right.flags & TypeFlags.Number ? getNumberLiteralType(+str) : + left.flags & TypeFlags.Enum ? left : right.flags & TypeFlags.Enum ? getNumberLiteralType(+str) : + left.flags & TypeFlags.NumberLiteral ? left : right.flags & TypeFlags.NumberLiteral && (right as NumberLiteralType).value === +str ? right : + left.flags & TypeFlags.BigInt ? left : right.flags & TypeFlags.BigInt ? parseBigIntLiteralType(str) : + left.flags & TypeFlags.BigIntLiteral ? left : right.flags & TypeFlags.BigIntLiteral && pseudoBigIntToString((right as BigIntLiteralType).value) === str ? right : + left.flags & TypeFlags.Boolean ? left : right.flags & TypeFlags.Boolean ? str === "true" ? trueType : str === "false" ? falseType : booleanType : + left.flags & TypeFlags.BooleanLiteral ? left : right.flags & TypeFlags.BooleanLiteral && (right as IntrinsicType).intrinsicName === str ? right : + left.flags & TypeFlags.Undefined ? left : right.flags & TypeFlags.Undefined && (right as IntrinsicType).intrinsicName === str ? right : + left.flags & TypeFlags.Null ? left : right.flags & TypeFlags.Null && (right as IntrinsicType).intrinsicName === str ? right : + left, + neverType as Type); + + if (!(matchingType.flags & TypeFlags.Never)) { + inferFromTypes(matchingType, target); + continue; + } + } + } + } + + inferFromTypes(source, target); } } } @@ -23410,13 +23524,16 @@ namespace ts { resolved.members.get("bind" as __String) && isTypeSubtypeOf(type, globalFunctionType)); } - function getTypeFacts(type: Type, ignoreObjects = false): TypeFacts { + function getTypeFacts(type: Type): TypeFacts { + if (type.flags & (TypeFlags.Intersection | TypeFlags.Instantiable)) { + type = getBaseConstraintOfType(type) || unknownType; + } const flags = type.flags; - if (flags & TypeFlags.String) { + if (flags & (TypeFlags.String | TypeFlags.StringMapping)) { return strictNullChecks ? TypeFacts.StringStrictFacts : TypeFacts.StringFacts; } - if (flags & TypeFlags.StringLiteral) { - const isEmpty = (type as StringLiteralType).value === ""; + if (flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral)) { + const isEmpty = flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === ""; return strictNullChecks ? isEmpty ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts : isEmpty ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; @@ -23448,16 +23565,16 @@ namespace ts { (type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts; } if (flags & TypeFlags.Object) { - if (ignoreObjects) { - return TypeFacts.AndFactsMask; // This is the identity element for computing type facts of intersection. - } return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type as ObjectType) ? strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts : isFunctionObjectType(type as ObjectType) ? strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts : strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; } - if (flags & (TypeFlags.Void | TypeFlags.Undefined)) { + if (flags & TypeFlags.Void) { + return TypeFacts.VoidFacts; + } + if (flags & TypeFlags.Undefined) { return TypeFacts.UndefinedFacts; } if (flags & TypeFlags.Null) { @@ -23472,31 +23589,29 @@ namespace ts { if (flags & TypeFlags.Never) { return TypeFacts.None; } - if (flags & TypeFlags.Instantiable) { - return !isPatternLiteralType(type) ? getTypeFacts(getBaseConstraintOfType(type) || unknownType, ignoreObjects) : - strictNullChecks ? TypeFacts.NonEmptyStringStrictFacts : TypeFacts.NonEmptyStringFacts; - } if (flags & TypeFlags.Union) { - return reduceLeft((type as UnionType).types, (facts, t) => facts | getTypeFacts(t, ignoreObjects), TypeFacts.None); + return reduceLeft((type as UnionType).types, (facts, t) => facts | getTypeFacts(t), TypeFacts.None); } if (flags & TypeFlags.Intersection) { - // When an intersection contains a primitive type we ignore object type constituents as they are - // presumably type tags. For example, in string & { __kind__: "name" } we ignore the object type. - ignoreObjects ||= maybeTypeOfKind(type, TypeFlags.Primitive); - return getIntersectionTypeFacts(type as IntersectionType, ignoreObjects); + return getIntersectionTypeFacts(type as IntersectionType); } - return TypeFacts.All; + return TypeFacts.UnknownFacts; } - function getIntersectionTypeFacts(type: IntersectionType, ignoreObjects: boolean): TypeFacts { + function getIntersectionTypeFacts(type: IntersectionType): TypeFacts { + // When an intersection contains a primitive type we ignore object type constituents as they are + // presumably type tags. For example, in string & { __kind__: "name" } we ignore the object type. + const ignoreObjects = maybeTypeOfKind(type, TypeFlags.Primitive); // When computing the type facts of an intersection type, certain type facts are computed as `and` // and others are computed as `or`. let oredFacts = TypeFacts.None; let andedFacts = TypeFacts.All; for (const t of type.types) { - const f = getTypeFacts(t, ignoreObjects); - oredFacts |= f; - andedFacts &= f; + if (!(ignoreObjects && t.flags & TypeFlags.Object)) { + const f = getTypeFacts(t); + oredFacts |= f; + andedFacts &= f; + } } return oredFacts & TypeFacts.OrFactsMask | andedFacts & TypeFacts.AndFactsMask; } @@ -23505,6 +23620,29 @@ namespace ts { return filterType(type, t => (getTypeFacts(t) & include) !== 0); } + // This function is similar to getTypeWithFacts, except that in strictNullChecks mode it replaces type + // unknown with the union {} | null | undefined (and reduces that accordingly), and it intersects remaining + // instantiable types with {}, {} | null, or {} | undefined in order to remove null and/or undefined. + function getAdjustedTypeWithFacts(type: Type, facts: TypeFacts) { + const reduced = recombineUnknownType(getTypeWithFacts(strictNullChecks && type.flags & TypeFlags.Unknown ? unknownUnionType : type, facts)); + if (strictNullChecks) { + switch (facts) { + case TypeFacts.NEUndefined: + return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQUndefined ? getIntersectionType([t, getTypeFacts(t) & TypeFacts.EQNull && !maybeTypeOfKind(reduced, TypeFlags.Null) ? getUnionType([emptyObjectType, nullType]) : emptyObjectType]): t); + case TypeFacts.NENull: + return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQNull ? getIntersectionType([t, getTypeFacts(t) & TypeFacts.EQUndefined && !maybeTypeOfKind(reduced, TypeFlags.Undefined) ? getUnionType([emptyObjectType, undefinedType]) : emptyObjectType]): t); + case TypeFacts.NEUndefinedOrNull: + case TypeFacts.Truthy: + return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQUndefinedOrNull ? getGlobalNonNullableTypeInstantiation(t): t); + } + } + return reduced; + } + + function recombineUnknownType(type: Type) { + return type === unknownUnionType ? unknownType : type; + } + function getTypeWithDefault(type: Type, defaultExpression: Expression) { return defaultExpression ? getUnionType([getNonUndefinedType(type), getTypeOfExpression(defaultExpression)]) : @@ -24636,7 +24774,7 @@ namespace ts { if (isEvolvingArrayTypeList(types)) { return getEvolvingArrayType(getUnionType(map(types, getElementTypeOfEvolvingArrayType))); } - const result = getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction); + const result = recombineUnknownType(getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction)); if (result !== declaredType && result.flags & declaredType.flags & TypeFlags.Union && arraysEqual((result as UnionType).types, (declaredType as UnionType).types)) { return declaredType; } @@ -24744,11 +24882,10 @@ namespace ts { function narrowTypeByTruthiness(type: Type, expr: Expression, assumeTrue: boolean): Type { if (isMatchingReference(reference, expr)) { - return type.flags & TypeFlags.Unknown && assumeTrue ? nonNullUnknownType : - getTypeWithFacts(type, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy); + return getAdjustedTypeWithFacts(type, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy); } if (strictNullChecks && assumeTrue && optionalChainContainsReference(expr, reference)) { - type = getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); } const access = getDiscriminantPropertyAccess(expr, type); if (access) { @@ -24894,7 +25031,7 @@ namespace ts { // Note that we include any and unknown in the exclusion test because their domain includes null and undefined. const removeNullable = equalsOperator !== assumeTrue && everyType(valueType, t => !!(t.flags & nullableFlags)) || equalsOperator === assumeTrue && everyType(valueType, t => !(t.flags & (TypeFlags.AnyOrUnknown | nullableFlags))); - return removeNullable ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; + return removeNullable ? getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; } function narrowTypeByEquality(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { @@ -24905,9 +25042,6 @@ namespace ts { assumeTrue = !assumeTrue; } const valueType = getTypeOfExpression(value); - if (assumeTrue && (type.flags & TypeFlags.Unknown) && (operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken) && (valueType.flags & TypeFlags.Null)) { - return getUnionType([nullType, undefinedType]); - } if ((type.flags & TypeFlags.Unknown) && assumeTrue && (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken)) { if (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) { return valueType; @@ -24927,7 +25061,7 @@ namespace ts { valueType.flags & TypeFlags.Null ? assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull : assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined; - return type.flags & TypeFlags.Unknown && facts & (TypeFacts.NENull | TypeFacts.NEUndefinedOrNull) ? nonNullUnknownType : getTypeWithFacts(type, facts); + return getAdjustedTypeWithFacts(type, facts); } if (assumeTrue) { const filterFn: (t: Type) => boolean = operator === SyntaxKind.EqualsEqualsToken ? @@ -24949,24 +25083,18 @@ namespace ts { const target = getReferenceCandidate(typeOfExpr.expression); if (!isMatchingReference(reference, target)) { if (strictNullChecks && optionalChainContainsReference(target, reference) && assumeTrue === (literal.text !== "undefined")) { - return getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + return getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); } return type; } if (type.flags & TypeFlags.Any && literal.text === "function") { return type; } - if (assumeTrue && type.flags & TypeFlags.Unknown && literal.text === "object") { - // The non-null unknown type is used to track whether a previous narrowing operation has removed the null type - // from the unknown type. For example, the expression `x && typeof x === 'object'` first narrows x to the non-null - // unknown type, and then narrows that to the non-primitive type. - return type === nonNullUnknownType ? nonPrimitiveType : getUnionType([nonPrimitiveType, nullType]); - } const facts = assumeTrue ? typeofEQFacts.get(literal.text) || TypeFacts.TypeofEQHostObject : typeofNEFacts.get(literal.text) || TypeFacts.TypeofNEHostObject; const impliedType = getImpliedTypeFromTypeofGuard(type, literal.text); - return getTypeWithFacts(assumeTrue && impliedType ? mapType(type, narrowUnionMemberByTypeof(impliedType)) : type, facts); + return getTypeWithFacts(assumeTrue && impliedType ? narrowTypeByImpliedType(type, impliedType) : type, facts); } function narrowTypeBySwitchOptionalChainContainment(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number, clauseCheck: (type: Type) => boolean) { @@ -25019,10 +25147,10 @@ namespace ts { function getImpliedTypeFromTypeofGuard(type: Type, text: string) { switch (text) { + case "object": + return type.flags & TypeFlags.Any ? type : getUnionType([nullType, nonPrimitiveType]); case "function": return type.flags & TypeFlags.Any ? type : globalFunctionType; - case "object": - return type.flags & TypeFlags.Unknown ? getUnionType([nonPrimitiveType, nullType]) : type; default: return typeofTypesByName.get(text); } @@ -25034,22 +25162,27 @@ namespace ts { // the guard. For example: narrowing `{} | undefined` by `"boolean"` should produce the type `boolean`, not // the filtered type `{}`. For this reason we narrow constituents of the union individually, in addition to // filtering by type-facts. - function narrowUnionMemberByTypeof(candidate: Type) { - return (type: Type) => { - if (isTypeSubtypeOf(type, candidate)) { - return type; + function narrowTypeByImpliedType(type: Type, candidate: Type) { + if (type.flags & TypeFlags.AnyOrUnknown) { + return candidate; + } + return mapType(type, t => { + if (isTypeRelatedTo(t, candidate, strictSubtypeRelation)) { + return t; } - if (isTypeSubtypeOf(candidate, type)) { - return candidate; - } - if (type.flags & TypeFlags.Instantiable) { - const constraint = getBaseConstraintOfType(type) || anyType; - if (isTypeSubtypeOf(candidate, constraint)) { - return getIntersectionType([type, candidate]); + return mapType(candidate, c => { + if (!areTypesComparable(t, c)) { + return neverType; } - } - return type; - }; + if (c.flags & TypeFlags.Primitive && t.flags & TypeFlags.Object && !isEmptyAnonymousObjectType(t)) { + return isTypeSubtypeOf(c, t) ? c : neverType; + } + if (c === globalFunctionType && isTypeSubtypeOf(c, t)) { + return c; + } + return getIntersectionType([t, c]); + }); + }); } function narrowBySwitchOnTypeOf(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): Type { @@ -25109,7 +25242,7 @@ namespace ts { because it is caught in the first clause. */ const impliedType = getTypeWithFacts(getUnionType(clauseWitnesses.map(text => getImpliedTypeFromTypeofGuard(type, text) || type)), switchFacts); - return getTypeWithFacts(mapType(type, narrowUnionMemberByTypeof(impliedType)), switchFacts); + return getTypeWithFacts(narrowTypeByImpliedType(type, impliedType), switchFacts); } function isMatchingConstructorReference(expr: Expression) { @@ -25170,7 +25303,7 @@ namespace ts { const left = getReferenceCandidate(expr.left); if (!isMatchingReference(reference, left)) { if (assumeTrue && strictNullChecks && optionalChainContainsReference(left, reference)) { - return getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + return getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); } return type; } @@ -25267,7 +25400,7 @@ namespace ts { } if (strictNullChecks && assumeTrue && optionalChainContainsReference(predicateArgument, reference) && !(getTypeFacts(predicate.type) & TypeFacts.EQUndefined)) { - type = getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); + type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); } const access = getDiscriminantPropertyAccess(predicateArgument, type); if (access) { @@ -25326,7 +25459,7 @@ namespace ts { function narrowTypeByOptionality(type: Type, expr: Expression, assumePresent: boolean): Type { if (isMatchingReference(reference, expr)) { - return getTypeWithFacts(type, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull); + return getAdjustedTypeWithFacts(type, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull); } const access = getDiscriminantPropertyAccess(expr, type); if (access) { @@ -25418,8 +25551,8 @@ namespace ts { const annotationIncludesUndefined = strictNullChecks && declaration.kind === SyntaxKind.Parameter && declaration.initializer && - getFalsyFlags(declaredType) & TypeFlags.Undefined && - !(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined); + getTypeFacts(declaredType) & TypeFacts.IsUndefined && + !(getTypeFacts(checkExpression(declaration.initializer)) & TypeFacts.IsUndefined); popTypeResolution(); return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType; @@ -25442,8 +25575,10 @@ namespace ts { !(someType(type, isGenericTypeWithoutNullableConstraint) && isGenericIndexType(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression))); } - function isGenericTypeWithUnionConstraint(type: Type) { - return !!(type.flags & TypeFlags.Instantiable && getBaseConstraintOrType(type).flags & (TypeFlags.Nullable | TypeFlags.Union)); + function isGenericTypeWithUnionConstraint(type: Type): boolean { + return type.flags & TypeFlags.Intersection ? + some((type as IntersectionType).types, isGenericTypeWithUnionConstraint) : + !!(type.flags & TypeFlags.Instantiable && getBaseConstraintOrType(type).flags & (TypeFlags.Nullable | TypeFlags.Union)); } function isGenericTypeWithoutNullableConstraint(type: Type) { @@ -25474,7 +25609,7 @@ namespace ts { const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) && someType(type, isGenericTypeWithUnionConstraint) && (isConstraintPosition(type, reference) || hasContextualTypeWithNoGenericTypes(reference, checkMode)); - return substituteConstraints ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOrType(t) : t) : type; + return substituteConstraints ? mapType(type, getBaseConstraintOrType) : type; } function isExportOrExportExpression(location: Node) { @@ -25774,7 +25909,7 @@ namespace ts { return convertAutoToAny(flowType); } } - else if (!assumeInitialized && !(getFalsyFlags(type) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) { + else if (!assumeInitialized && !(getTypeFacts(type) & TypeFacts.IsUndefined) && getTypeFacts(flowType) & TypeFacts.IsUndefined) { error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol)); // Return the declared type to reduce follow-on errors return type; @@ -28751,23 +28886,23 @@ namespace ts { } function isNullableType(type: Type) { - return !!((strictNullChecks ? getFalsyFlags(type) : type.flags) & TypeFlags.Nullable); + return !!(getTypeFacts(type) & TypeFacts.IsUndefinedOrNull); } function getNonNullableTypeIfNeeded(type: Type) { return isNullableType(type) ? getNonNullableType(type) : type; } - function reportObjectPossiblyNullOrUndefinedError(node: Node, flags: TypeFlags) { - error(node, flags & TypeFlags.Undefined ? flags & TypeFlags.Null ? + function reportObjectPossiblyNullOrUndefinedError(node: Node, facts: TypeFacts) { + error(node, facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? Diagnostics.Object_is_possibly_null_or_undefined : Diagnostics.Object_is_possibly_undefined : Diagnostics.Object_is_possibly_null ); } - function reportCannotInvokePossiblyNullOrUndefinedError(node: Node, flags: TypeFlags) { - error(node, flags & TypeFlags.Undefined ? flags & TypeFlags.Null ? + function reportCannotInvokePossiblyNullOrUndefinedError(node: Node, facts: TypeFacts) { + error(node, facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? Diagnostics.Cannot_invoke_an_object_which_is_possibly_null_or_undefined : Diagnostics.Cannot_invoke_an_object_which_is_possibly_undefined : Diagnostics.Cannot_invoke_an_object_which_is_possibly_null @@ -28777,15 +28912,15 @@ namespace ts { function checkNonNullTypeWithReporter( type: Type, node: Node, - reportError: (node: Node, kind: TypeFlags) => void + reportError: (node: Node, facts: TypeFacts) => void ): Type { if (strictNullChecks && type.flags & TypeFlags.Unknown) { error(node, Diagnostics.Object_is_of_type_unknown); return errorType; } - const kind = (strictNullChecks ? getFalsyFlags(type) : type.flags) & TypeFlags.Nullable; - if (kind) { - reportError(node, kind); + const facts = getTypeFacts(type); + if (facts & TypeFacts.IsUndefinedOrNull) { + reportError(node, facts); const t = getNonNullableType(type); return t.flags & (TypeFlags.Nullable | TypeFlags.Never) ? errorType : t; } @@ -29131,7 +29266,7 @@ namespace ts { assumeUninitialized = true; } const flowType = getFlowTypeOfReference(node, propType, assumeUninitialized ? getOptionalType(propType) : propType); - if (assumeUninitialized && !(getFalsyFlags(propType) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) { + if (assumeUninitialized && !(getTypeFacts(propType) & TypeFacts.IsUndefined) && getTypeFacts(flowType) & TypeFacts.IsUndefined) { error(errorNode, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(prop!)); // TODO: GH#18217 // Return the declared type to reduce follow-on errors return propType; @@ -33118,7 +33253,7 @@ namespace ts { const type = getTypeOfSymbol(symbol); if (strictNullChecks && !(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Never)) && - !(exactOptionalPropertyTypes ? symbol.flags & SymbolFlags.Optional : getFalsyFlags(type) & TypeFlags.Undefined)) { + !(exactOptionalPropertyTypes ? symbol.flags & SymbolFlags.Optional : getTypeFacts(type) & TypeFacts.IsUndefined)) { error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_optional); } } @@ -33555,7 +33690,7 @@ namespace ts { // In strict null checking mode, if a default value of a non-undefined type is specified, remove // undefined from the final type. if (strictNullChecks && - !(getFalsyFlags(checkExpression(prop.objectAssignmentInitializer)) & TypeFlags.Undefined)) { + !(getTypeFacts(checkExpression(prop.objectAssignmentInitializer)) & TypeFacts.IsUndefined)) { sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined); } checkBinaryLikeExpression(prop.name, prop.equalsToken!, prop.objectAssignmentInitializer, checkMode); @@ -34014,7 +34149,7 @@ namespace ts { case SyntaxKind.BarBarToken: case SyntaxKind.BarBarEqualsToken: { const resultType = getTypeFacts(leftType) & TypeFacts.Falsy ? - getUnionType([removeDefinitelyFalsyTypes(leftType), rightType], UnionReduction.Subtype) : + getUnionType([getNonNullableType(removeDefinitelyFalsyTypes(leftType)), rightType], UnionReduction.Subtype) : leftType; if (operator === SyntaxKind.BarBarEqualsToken) { checkAssignmentOperator(rightType); @@ -37793,7 +37928,7 @@ namespace ts { // For a binding pattern, validate the initializer and exit if (isBindingPattern(node.name)) { const needCheckInitializer = node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement; - const needCheckWidenedType = node.name.elements.length === 0; + const needCheckWidenedType = !some(node.name.elements, not(isOmittedExpression)); if (needCheckInitializer || needCheckWidenedType) { // Don't validate for-in initializer as it is already an error const widenedType = getWidenedTypeForVariableLikeDeclaration(node); @@ -37969,7 +38104,7 @@ namespace ts { if (isModuleExportsAccessExpression(location)) return; const type = checkTruthinessExpression(location); const isPropertyExpressionCast = isPropertyAccessExpression(location) && isTypeAssertion(location.expression); - if (getFalsyFlags(type) || isPropertyExpressionCast) return; + if (!(getTypeFacts(type) & TypeFacts.Truthy) || isPropertyExpressionCast) return; // While it technically should be invalid for any known-truthy value // to be tested, we de-scope to functions and Promises unreferenced in @@ -39962,10 +40097,13 @@ namespace ts { const derivedPropertyFlags = derived.flags & SymbolFlags.PropertyOrAccessor; if (basePropertyFlags && derivedPropertyFlags) { // property/accessor is overridden with property/accessor - if (baseDeclarationFlags & ModifierFlags.Abstract && !(base.valueDeclaration && isPropertyDeclaration(base.valueDeclaration) && base.valueDeclaration.initializer) - || base.valueDeclaration && base.valueDeclaration.parent.kind === SyntaxKind.InterfaceDeclaration + if ((getCheckFlags(base) & CheckFlags.Synthetic + ? base.declarations?.some(d => isPropertyAbstractOrInterface(d, baseDeclarationFlags)) + : base.declarations?.every(d => isPropertyAbstractOrInterface(d, baseDeclarationFlags))) + || getCheckFlags(base) & CheckFlags.Mapped || derived.valueDeclaration && isBinaryExpression(derived.valueDeclaration)) { // when the base property is abstract or from an interface, base/derived flags don't need to match + // for intersection properties, this must be true of *any* of the declarations, for others it must be true of *all* // same when the derived property is from an assignment continue; } @@ -40023,7 +40161,12 @@ namespace ts { } } - function getNonInterhitedProperties(type: InterfaceType, baseTypes: BaseType[], properties: Symbol[]) { + function isPropertyAbstractOrInterface(declaration: Declaration, baseDeclarationFlags: ModifierFlags) { + return baseDeclarationFlags & ModifierFlags.Abstract && (!isPropertyDeclaration(declaration) || !declaration.initializer) + || isInterfaceDeclaration(declaration.parent); + } + + function getNonInheritedProperties(type: InterfaceType, baseTypes: BaseType[], properties: Symbol[]) { if (!length(baseTypes)) { return properties; } @@ -40097,7 +40240,7 @@ namespace ts { const propName = (member as PropertyDeclaration).name; if (isIdentifier(propName) || isPrivateIdentifier(propName) || isComputedPropertyName(propName)) { const type = getTypeOfSymbol(getSymbolOfNode(member)); - if (!(type.flags & TypeFlags.AnyOrUnknown || getFalsyFlags(type) & TypeFlags.Undefined)) { + if (!(type.flags & TypeFlags.AnyOrUnknown || getTypeFacts(type) & TypeFacts.IsUndefined)) { if (!constructor || !isPropertyInitializedInConstructor(propName, type, constructor)) { error(member.name, Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor, declarationNameToString(propName)); } @@ -40123,7 +40266,7 @@ namespace ts { setParent(reference, staticBlock); reference.flowNode = staticBlock.returnFlowNode; const flowType = getFlowTypeOfReference(reference, propType, getOptionalType(propType)); - if (!(getFalsyFlags(flowType) & TypeFlags.Undefined)) { + if (!(getTypeFacts(flowType) & TypeFacts.IsUndefined)) { return true; } } @@ -40139,7 +40282,7 @@ namespace ts { setParent(reference, constructor); reference.flowNode = constructor.returnFlowNode; const flowType = getFlowTypeOfReference(reference, propType, getOptionalType(propType)); - return !(getFalsyFlags(flowType) & TypeFlags.Undefined); + return !(getTypeFacts(flowType) & TypeFacts.IsUndefined); } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index d0eaa7fc0dc..a80e151ca74 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2035,7 +2035,7 @@ namespace ts { return comparer(a, b); } - export function compareProperties(a: T | undefined, b: T | undefined, key: K, comparer: Comparer): Comparison { + export function compareProperties(a: T | undefined, b: T | undefined, key: K, comparer: Comparer): Comparison { return a === b ? Comparison.EqualTo : a === undefined ? Comparison.LessThan : b === undefined ? Comparison.GreaterThan : diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 81012bd0580..09e4c8756ba 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1526,6 +1526,10 @@ "category": "Error", "code": 2207 }, + "This type parameter probably needs an `extends object` constraint.": { + "category": "Error", + "code": 2208 + }, "The project root is ambiguous, but is required to resolve export map entry '{0}' in file '{1}'. Supply the `rootDir` compiler option to disambiguate.": { "category": "Error", @@ -3471,6 +3475,10 @@ "category": "Error", "code": 2839 }, + "An interface cannot extend a primitive type like '{0}'; an interface can only extend named types and classes": { + "category": "Error", + "code": 2840 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index d2b0db1041b..fc62e3ee01b 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -2413,8 +2413,8 @@ namespace ts { ); if ( !pathAndExtension && packageInfo - && packageInfo.packageJsonContent.exports === undefined - && packageInfo.packageJsonContent.main === undefined + // eslint-disable-next-line no-null/no-null + && (packageInfo.packageJsonContent.exports === undefined || packageInfo.packageJsonContent.exports === null) && state.features & NodeResolutionFeatures.EsmMode ) { // EsmMode disables index lookup in `loadNodeModuleFromDirectoryWorker` generally, however non-relative package resolutions still assume diff --git a/src/compiler/types.ts b/src/compiler/types.ts index cfc21f8f957..3d3243eded6 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5398,6 +5398,11 @@ namespace ts { // Flags that require TypeFlags.Union /* @internal */ ContainsIntersections = 1 << 24, // Union contains intersections + /* @internal */ + IsUnknownLikeUnionComputed = 1 << 25, // IsUnknownLikeUnion flag has been computed + /* @internal */ + IsUnknownLikeUnion = 1 << 26, // Union of null, undefined, and empty object type + /* @internal */ // Flags that require TypeFlags.Intersection /* @internal */ @@ -5878,7 +5883,7 @@ namespace ts { AlwaysStrict = 1 << 10, // Always use strict rules for contravariant inferences MaxValue = 1 << 11, // Seed for inference priority tracking - PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates + PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates Circularity = -1, // Inference circularity (value less than all other priorities) } diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index 75b9539cc75..754f6655db1 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -1564,7 +1564,7 @@ type Omit = Pick>; /** * Exclude null and undefined from T */ -type NonNullable = T extends null | undefined ? never : T; +type NonNullable = T & {}; /** * Obtain the parameters of a function type in a tuple diff --git a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl index 758e90ecbf4..14dcca5a22a 100644 --- a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13803,6 +13803,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl index 317e0f3d615..53a0b60c590 100644 --- a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13803,6 +13803,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl index f23153e6d0d..af0e3ebe382 100644 --- a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13812,6 +13812,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl index 0297c8f16c1..866081e52ab 100644 --- a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13797,6 +13797,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl index 4de3f85619d..eed73b0c11f 100644 --- a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13815,6 +13815,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl index 2e741c3cf17..e4d07b9627e 100644 --- a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13815,6 +13815,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl index 7a7125b04e3..68ab2f13979 100644 --- a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13803,6 +13803,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl index b726eda4716..db9ab9bcb20 100644 --- a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13803,6 +13803,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl index 7b67b250d52..3aa469387e2 100644 --- a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13803,6 +13803,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 37ea7a94809..e3ab0e967d6 100644 --- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13790,6 +13790,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl index 6f737dae47e..215efea1553 100644 --- a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13793,6 +13793,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl index e9e437101c7..5ceeeb915f0 100644 --- a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13802,6 +13802,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl index d76cc781655..a1fcfdc4e93 100644 --- a/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -13796,6 +13796,15 @@ + + + + + + + + + diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 256398d9a20..789fcb12c58 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -617,7 +617,6 @@ namespace ts.formatting { case SyntaxKind.JsxOpeningElement: case SyntaxKind.JsxClosingElement: case SyntaxKind.JsxSelfClosingElement: - case SyntaxKind.ExpressionWithTypeArguments: return false; } break; @@ -835,7 +834,7 @@ namespace ts.formatting { const listEndToken = getCloseTokenForOpenToken(listStartToken); if (listEndToken !== SyntaxKind.Unknown && formattingScanner.isOnToken() && formattingScanner.getStartPos() < originalRange.end) { let tokenInfo: TokenInfo | undefined = formattingScanner.readTokenInfo(parent); - if (tokenInfo.token.kind === SyntaxKind.CommaToken && isCallLikeExpression(parent)) { + if (tokenInfo.token.kind === SyntaxKind.CommaToken) { // consume the comma consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent); tokenInfo = formattingScanner.isOnToken() ? formattingScanner.readTokenInfo(parent) : undefined; @@ -1311,6 +1310,12 @@ namespace ts.formatting { case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: case SyntaxKind.ArrowFunction: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: if ((node as FunctionDeclaration).typeParameters === list) { return SyntaxKind.LessThanToken; } @@ -1327,7 +1332,19 @@ namespace ts.formatting { return SyntaxKind.OpenParenToken; } break; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: + if ((node as ClassDeclaration).typeParameters === list) { + return SyntaxKind.LessThanToken; + } + break; case SyntaxKind.TypeReference: + case SyntaxKind.TaggedTemplateExpression: + case SyntaxKind.TypeQuery: + case SyntaxKind.ExpressionWithTypeArguments: + case SyntaxKind.ImportType: if ((node as TypeReferenceNode).typeArguments === list) { return SyntaxKind.LessThanToken; } diff --git a/src/services/inlayHints.ts b/src/services/inlayHints.ts index ca95df202b8..e00ca3308d5 100644 --- a/src/services/inlayHints.ts +++ b/src/services/inlayHints.ts @@ -47,7 +47,7 @@ namespace ts.InlayHints { return; } - if (isTypeNode(node)) { + if (isTypeNode(node) && !isExpressionWithTypeArguments(node)) { return; } diff --git a/test.js b/test.js new file mode 100644 index 00000000000..ba63496c717 --- /dev/null +++ b/test.js @@ -0,0 +1,9 @@ +"use strict"; +exports.__esModule = true; +exports.main = void 0; +function main() { + for (var _i = 0, doesNotExist_1 = doesNotExist; _i < doesNotExist_1.length; _i++) { + var _a = doesNotExist_1[_i]; + } +} +exports.main = main; diff --git a/test.ts b/test.ts new file mode 100644 index 00000000000..9f0f9667697 --- /dev/null +++ b/test.ts @@ -0,0 +1,4 @@ +export function main() { + for (const [,] of doesNotExist) { + } +} \ No newline at end of file diff --git a/tests/baselines/reference/accessorsOverrideProperty8.js b/tests/baselines/reference/accessorsOverrideProperty8.js new file mode 100644 index 00000000000..bd51c4b9afb --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty8.js @@ -0,0 +1,50 @@ +//// [accessorsOverrideProperty8.ts] +type Types = 'boolean' | 'unknown' | 'string'; + +type Properties = { + readonly [key in keyof T]: T[key] extends 'boolean' ? boolean : T[key] extends 'string' ? string : unknown +} + +type AnyCtor

= new (...a: any[]) => P + +declare function classWithProperties(properties: T, klass: AnyCtor

): { + new(): P & Properties; + prototype: P & Properties +}; + +const Base = classWithProperties({ + get x() { return 'boolean' as const }, + y: 'string', +}, class Base { +}); + +class MyClass extends Base { + get x() { + return false; + } + get y() { + return 'hi' + } +} + +const mine = new MyClass(); +const value = mine.x; + + + +//// [accessorsOverrideProperty8.js] +const Base = classWithProperties({ + get x() { return 'boolean'; }, + y: 'string', +}, class Base { +}); +class MyClass extends Base { + get x() { + return false; + } + get y() { + return 'hi'; + } +} +const mine = new MyClass(); +const value = mine.x; diff --git a/tests/baselines/reference/accessorsOverrideProperty8.symbols b/tests/baselines/reference/accessorsOverrideProperty8.symbols new file mode 100644 index 00000000000..7e60b8c582d --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty8.symbols @@ -0,0 +1,93 @@ +=== tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts === +type Types = 'boolean' | 'unknown' | 'string'; +>Types : Symbol(Types, Decl(accessorsOverrideProperty8.ts, 0, 0)) + +type Properties = { +>Properties : Symbol(Properties, Decl(accessorsOverrideProperty8.ts, 0, 46)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 2, 16)) +>key : Symbol(key, Decl(accessorsOverrideProperty8.ts, 2, 29)) +>Types : Symbol(Types, Decl(accessorsOverrideProperty8.ts, 0, 0)) + + readonly [key in keyof T]: T[key] extends 'boolean' ? boolean : T[key] extends 'string' ? string : unknown +>key : Symbol(key, Decl(accessorsOverrideProperty8.ts, 3, 14)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 2, 16)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 2, 16)) +>key : Symbol(key, Decl(accessorsOverrideProperty8.ts, 3, 14)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 2, 16)) +>key : Symbol(key, Decl(accessorsOverrideProperty8.ts, 3, 14)) +} + +type AnyCtor

= new (...a: any[]) => P +>AnyCtor : Symbol(AnyCtor, Decl(accessorsOverrideProperty8.ts, 4, 1)) +>P : Symbol(P, Decl(accessorsOverrideProperty8.ts, 6, 13)) +>a : Symbol(a, Decl(accessorsOverrideProperty8.ts, 6, 38)) +>P : Symbol(P, Decl(accessorsOverrideProperty8.ts, 6, 13)) + +declare function classWithProperties(properties: T, klass: AnyCtor

): { +>classWithProperties : Symbol(classWithProperties, Decl(accessorsOverrideProperty8.ts, 6, 55)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 8, 37)) +>key : Symbol(key, Decl(accessorsOverrideProperty8.ts, 8, 50)) +>Types : Symbol(Types, Decl(accessorsOverrideProperty8.ts, 0, 0)) +>P : Symbol(P, Decl(accessorsOverrideProperty8.ts, 8, 72)) +>properties : Symbol(properties, Decl(accessorsOverrideProperty8.ts, 8, 91)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 8, 37)) +>klass : Symbol(klass, Decl(accessorsOverrideProperty8.ts, 8, 105)) +>AnyCtor : Symbol(AnyCtor, Decl(accessorsOverrideProperty8.ts, 4, 1)) +>P : Symbol(P, Decl(accessorsOverrideProperty8.ts, 8, 72)) + + new(): P & Properties; +>P : Symbol(P, Decl(accessorsOverrideProperty8.ts, 8, 72)) +>Properties : Symbol(Properties, Decl(accessorsOverrideProperty8.ts, 0, 46)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 8, 37)) + + prototype: P & Properties +>prototype : Symbol(prototype, Decl(accessorsOverrideProperty8.ts, 9, 29)) +>P : Symbol(P, Decl(accessorsOverrideProperty8.ts, 8, 72)) +>Properties : Symbol(Properties, Decl(accessorsOverrideProperty8.ts, 0, 46)) +>T : Symbol(T, Decl(accessorsOverrideProperty8.ts, 8, 37)) + +}; + +const Base = classWithProperties({ +>Base : Symbol(Base, Decl(accessorsOverrideProperty8.ts, 13, 5)) +>classWithProperties : Symbol(classWithProperties, Decl(accessorsOverrideProperty8.ts, 6, 55)) + + get x() { return 'boolean' as const }, +>x : Symbol(x, Decl(accessorsOverrideProperty8.ts, 13, 34)) +>const : Symbol(const) + + y: 'string', +>y : Symbol(y, Decl(accessorsOverrideProperty8.ts, 14, 42)) + +}, class Base { +>Base : Symbol(Base, Decl(accessorsOverrideProperty8.ts, 16, 2)) + +}); + +class MyClass extends Base { +>MyClass : Symbol(MyClass, Decl(accessorsOverrideProperty8.ts, 17, 3)) +>Base : Symbol(Base, Decl(accessorsOverrideProperty8.ts, 13, 5)) + + get x() { +>x : Symbol(MyClass.x, Decl(accessorsOverrideProperty8.ts, 19, 28)) + + return false; + } + get y() { +>y : Symbol(MyClass.y, Decl(accessorsOverrideProperty8.ts, 22, 5)) + + return 'hi' + } +} + +const mine = new MyClass(); +>mine : Symbol(mine, Decl(accessorsOverrideProperty8.ts, 28, 5)) +>MyClass : Symbol(MyClass, Decl(accessorsOverrideProperty8.ts, 17, 3)) + +const value = mine.x; +>value : Symbol(value, Decl(accessorsOverrideProperty8.ts, 29, 5)) +>mine.x : Symbol(MyClass.x, Decl(accessorsOverrideProperty8.ts, 19, 28)) +>mine : Symbol(mine, Decl(accessorsOverrideProperty8.ts, 28, 5)) +>x : Symbol(MyClass.x, Decl(accessorsOverrideProperty8.ts, 19, 28)) + + diff --git a/tests/baselines/reference/accessorsOverrideProperty8.types b/tests/baselines/reference/accessorsOverrideProperty8.types new file mode 100644 index 00000000000..1379593d280 --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty8.types @@ -0,0 +1,78 @@ +=== tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts === +type Types = 'boolean' | 'unknown' | 'string'; +>Types : "string" | "boolean" | "unknown" + +type Properties = { +>Properties : Properties +>key : string + + readonly [key in keyof T]: T[key] extends 'boolean' ? boolean : T[key] extends 'string' ? string : unknown +} + +type AnyCtor

= new (...a: any[]) => P +>AnyCtor : AnyCtor

+>a : any[] + +declare function classWithProperties(properties: T, klass: AnyCtor

): { +>classWithProperties : (properties: T, klass: AnyCtor

) => { new (): P & Properties; prototype: P & Properties;} +>key : string +>properties : T +>klass : AnyCtor

+ + new(): P & Properties; + prototype: P & Properties +>prototype : P & Properties + +}; + +const Base = classWithProperties({ +>Base : { new (): Base & Properties<{ readonly x: "boolean"; y: "string"; }>; prototype: Base & Properties<{ readonly x: "boolean"; y: "string"; }>; } +>classWithProperties({ get x() { return 'boolean' as const }, y: 'string',}, class Base {}) : { new (): Base & Properties<{ readonly x: "boolean"; y: "string"; }>; prototype: Base & Properties<{ readonly x: "boolean"; y: "string"; }>; } +>classWithProperties : (properties: T, klass: AnyCtor

) => { new (): P & Properties; prototype: P & Properties; } +>{ get x() { return 'boolean' as const }, y: 'string',} : { readonly x: "boolean"; y: "string"; } + + get x() { return 'boolean' as const }, +>x : "boolean" +>'boolean' as const : "boolean" +>'boolean' : "boolean" + + y: 'string', +>y : "string" +>'string' : "string" + +}, class Base { +>class Base {} : typeof Base +>Base : typeof Base + +}); + +class MyClass extends Base { +>MyClass : MyClass +>Base : Base & Properties<{ readonly x: "boolean"; y: "string"; }> + + get x() { +>x : boolean + + return false; +>false : false + } + get y() { +>y : string + + return 'hi' +>'hi' : "hi" + } +} + +const mine = new MyClass(); +>mine : MyClass +>new MyClass() : MyClass +>MyClass : typeof MyClass + +const value = mine.x; +>value : boolean +>mine.x : boolean +>mine : MyClass +>x : boolean + + diff --git a/tests/baselines/reference/accessorsOverrideProperty9.js b/tests/baselines/reference/accessorsOverrideProperty9.js new file mode 100644 index 00000000000..a1b8d7bde87 --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty9.js @@ -0,0 +1,79 @@ +//// [accessorsOverrideProperty9.ts] +// #41347, based on microsoft/rushstack + +// Mixin utilities +export type Constructor = new (...args: any[]) => T; +export type PropertiesOf = { [K in keyof T]: T[K] }; + +interface IApiItemConstructor extends Constructor, PropertiesOf {} + +// Base class +class ApiItem { + public get members(): ReadonlyArray { + return []; + } +} + +// Normal subclass +class ApiEnumMember extends ApiItem { +} + +// Mixin base class +interface ApiItemContainerMixin extends ApiItem { + readonly members: ReadonlyArray; +} + +function ApiItemContainerMixin( + baseClass: TBaseClass +): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) { + abstract class MixedClass extends baseClass implements ApiItemContainerMixin { + public constructor(...args: any[]) { + super(...args); + } + + public get members(): ReadonlyArray { + return []; + } + } + + return MixedClass; +} + +// Subclass inheriting from mixin +export class ApiEnum extends ApiItemContainerMixin(ApiItem) { + // This worked prior to TypeScript 4.0: + public get members(): ReadonlyArray { + return []; + } +} + + +//// [accessorsOverrideProperty9.js] +// #41347, based on microsoft/rushstack +// Base class +class ApiItem { + get members() { + return []; + } +} +// Normal subclass +class ApiEnumMember extends ApiItem { +} +function ApiItemContainerMixin(baseClass) { + class MixedClass extends baseClass { + constructor(...args) { + super(...args); + } + get members() { + return []; + } + } + return MixedClass; +} +// Subclass inheriting from mixin +export class ApiEnum extends ApiItemContainerMixin(ApiItem) { + // This worked prior to TypeScript 4.0: + get members() { + return []; + } +} diff --git a/tests/baselines/reference/accessorsOverrideProperty9.symbols b/tests/baselines/reference/accessorsOverrideProperty9.symbols new file mode 100644 index 00000000000..5195876798a --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty9.symbols @@ -0,0 +1,111 @@ +=== tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty9.ts === +// #41347, based on microsoft/rushstack + +// Mixin utilities +export type Constructor = new (...args: any[]) => T; +>Constructor : Symbol(Constructor, Decl(accessorsOverrideProperty9.ts, 0, 0)) +>T : Symbol(T, Decl(accessorsOverrideProperty9.ts, 3, 24)) +>args : Symbol(args, Decl(accessorsOverrideProperty9.ts, 3, 39)) +>T : Symbol(T, Decl(accessorsOverrideProperty9.ts, 3, 24)) + +export type PropertiesOf = { [K in keyof T]: T[K] }; +>PropertiesOf : Symbol(PropertiesOf, Decl(accessorsOverrideProperty9.ts, 3, 60)) +>T : Symbol(T, Decl(accessorsOverrideProperty9.ts, 4, 25)) +>K : Symbol(K, Decl(accessorsOverrideProperty9.ts, 4, 33)) +>T : Symbol(T, Decl(accessorsOverrideProperty9.ts, 4, 25)) +>T : Symbol(T, Decl(accessorsOverrideProperty9.ts, 4, 25)) +>K : Symbol(K, Decl(accessorsOverrideProperty9.ts, 4, 33)) + +interface IApiItemConstructor extends Constructor, PropertiesOf {} +>IApiItemConstructor : Symbol(IApiItemConstructor, Decl(accessorsOverrideProperty9.ts, 4, 55)) +>Constructor : Symbol(Constructor, Decl(accessorsOverrideProperty9.ts, 0, 0)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) +>PropertiesOf : Symbol(PropertiesOf, Decl(accessorsOverrideProperty9.ts, 3, 60)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) + +// Base class +class ApiItem { +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) + + public get members(): ReadonlyArray { +>members : Symbol(ApiItem.members, Decl(accessorsOverrideProperty9.ts, 9, 15)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) + + return []; + } +} + +// Normal subclass +class ApiEnumMember extends ApiItem { +>ApiEnumMember : Symbol(ApiEnumMember, Decl(accessorsOverrideProperty9.ts, 13, 1)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) +} + +// Mixin base class +interface ApiItemContainerMixin extends ApiItem { +>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty9.ts, 22, 1), Decl(accessorsOverrideProperty9.ts, 17, 1)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) + + readonly members: ReadonlyArray; +>members : Symbol(ApiItemContainerMixin.members, Decl(accessorsOverrideProperty9.ts, 20, 49)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) +} + +function ApiItemContainerMixin( +>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty9.ts, 22, 1), Decl(accessorsOverrideProperty9.ts, 17, 1)) +>TBaseClass : Symbol(TBaseClass, Decl(accessorsOverrideProperty9.ts, 24, 31)) +>IApiItemConstructor : Symbol(IApiItemConstructor, Decl(accessorsOverrideProperty9.ts, 4, 55)) + + baseClass: TBaseClass +>baseClass : Symbol(baseClass, Decl(accessorsOverrideProperty9.ts, 24, 71)) +>TBaseClass : Symbol(TBaseClass, Decl(accessorsOverrideProperty9.ts, 24, 31)) + +): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) { +>TBaseClass : Symbol(TBaseClass, Decl(accessorsOverrideProperty9.ts, 24, 31)) +>args : Symbol(args, Decl(accessorsOverrideProperty9.ts, 26, 22)) +>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty9.ts, 22, 1), Decl(accessorsOverrideProperty9.ts, 17, 1)) + + abstract class MixedClass extends baseClass implements ApiItemContainerMixin { +>MixedClass : Symbol(MixedClass, Decl(accessorsOverrideProperty9.ts, 26, 65)) +>baseClass : Symbol(baseClass, Decl(accessorsOverrideProperty9.ts, 24, 71)) +>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty9.ts, 22, 1), Decl(accessorsOverrideProperty9.ts, 17, 1)) + + public constructor(...args: any[]) { +>args : Symbol(args, Decl(accessorsOverrideProperty9.ts, 28, 23)) + + super(...args); +>super : Symbol(TBaseClass, Decl(accessorsOverrideProperty9.ts, 24, 31)) +>args : Symbol(args, Decl(accessorsOverrideProperty9.ts, 28, 23)) + } + + public get members(): ReadonlyArray { +>members : Symbol(MixedClass.members, Decl(accessorsOverrideProperty9.ts, 30, 5)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) + + return []; + } + } + + return MixedClass; +>MixedClass : Symbol(MixedClass, Decl(accessorsOverrideProperty9.ts, 26, 65)) +} + +// Subclass inheriting from mixin +export class ApiEnum extends ApiItemContainerMixin(ApiItem) { +>ApiEnum : Symbol(ApiEnum, Decl(accessorsOverrideProperty9.ts, 38, 1)) +>ApiItemContainerMixin : Symbol(ApiItemContainerMixin, Decl(accessorsOverrideProperty9.ts, 22, 1), Decl(accessorsOverrideProperty9.ts, 17, 1)) +>ApiItem : Symbol(ApiItem, Decl(accessorsOverrideProperty9.ts, 6, 91)) + + // This worked prior to TypeScript 4.0: + public get members(): ReadonlyArray { +>members : Symbol(ApiEnum.members, Decl(accessorsOverrideProperty9.ts, 41, 61)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --)) +>ApiEnumMember : Symbol(ApiEnumMember, Decl(accessorsOverrideProperty9.ts, 13, 1)) + + return []; + } +} + diff --git a/tests/baselines/reference/accessorsOverrideProperty9.types b/tests/baselines/reference/accessorsOverrideProperty9.types new file mode 100644 index 00000000000..dcbc3523e10 --- /dev/null +++ b/tests/baselines/reference/accessorsOverrideProperty9.types @@ -0,0 +1,89 @@ +=== tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty9.ts === +// #41347, based on microsoft/rushstack + +// Mixin utilities +export type Constructor = new (...args: any[]) => T; +>Constructor : Constructor +>args : any[] + +export type PropertiesOf = { [K in keyof T]: T[K] }; +>PropertiesOf : PropertiesOf + +interface IApiItemConstructor extends Constructor, PropertiesOf {} +>ApiItem : typeof ApiItem + +// Base class +class ApiItem { +>ApiItem : ApiItem + + public get members(): ReadonlyArray { +>members : readonly ApiItem[] + + return []; +>[] : never[] + } +} + +// Normal subclass +class ApiEnumMember extends ApiItem { +>ApiEnumMember : ApiEnumMember +>ApiItem : ApiItem +} + +// Mixin base class +interface ApiItemContainerMixin extends ApiItem { + readonly members: ReadonlyArray; +>members : readonly ApiItem[] +} + +function ApiItemContainerMixin( +>ApiItemContainerMixin : (baseClass: TBaseClass) => TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) + + baseClass: TBaseClass +>baseClass : TBaseClass + +): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) { +>args : any[] + + abstract class MixedClass extends baseClass implements ApiItemContainerMixin { +>MixedClass : MixedClass +>baseClass : ApiItem + + public constructor(...args: any[]) { +>args : any[] + + super(...args); +>super(...args) : void +>super : TBaseClass +>...args : any +>args : any[] + } + + public get members(): ReadonlyArray { +>members : readonly ApiItem[] + + return []; +>[] : never[] + } + } + + return MixedClass; +>MixedClass : ((abstract new (...args: any[]) => MixedClass) & { prototype: ApiItemContainerMixin.MixedClass; }) & TBaseClass +} + +// Subclass inheriting from mixin +export class ApiEnum extends ApiItemContainerMixin(ApiItem) { +>ApiEnum : ApiEnum +>ApiItemContainerMixin(ApiItem) : ApiItem & ApiItemContainerMixin +>ApiItemContainerMixin : (baseClass: TBaseClass) => TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) +>ApiItem : typeof ApiItem + + // This worked prior to TypeScript 4.0: + public get members(): ReadonlyArray { +>members : readonly ApiEnumMember[] + + return []; +>[] : never[] + } +} + diff --git a/tests/baselines/reference/assertionTypePredicates1.types b/tests/baselines/reference/assertionTypePredicates1.types index 064cf6066f4..c8f4c2e063a 100644 --- a/tests/baselines/reference/assertionTypePredicates1.types +++ b/tests/baselines/reference/assertionTypePredicates1.types @@ -150,7 +150,7 @@ function f01(x: unknown) { >undefined : undefined >typeof x === "string" : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} | null >"string" : "string" x; // string | undefined diff --git a/tests/baselines/reference/conditionalTypes1.errors.txt b/tests/baselines/reference/conditionalTypes1.errors.txt index 85f50cb0e7d..f411c6270e8 100644 --- a/tests/baselines/reference/conditionalTypes1.errors.txt +++ b/tests/baselines/reference/conditionalTypes1.errors.txt @@ -1,12 +1,23 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(12,5): error TS2322: Type 'T' is not assignable to type 'NonNullable'. + Type 'T' is not assignable to type '{}'. tests/cases/conformance/types/conditional/conditionalTypes1.ts(17,5): error TS2322: Type 'T' is not assignable to type 'NonNullable'. Type 'string | undefined' is not assignable to type 'NonNullable'. Type 'undefined' is not assignable to type 'NonNullable'. + Type 'undefined' is not assignable to type 'T'. + 'undefined' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string | undefined'. + Type 'T' is not assignable to type '{}'. + Type 'string | undefined' is not assignable to type '{}'. + Type 'undefined' is not assignable to type '{}'. tests/cases/conformance/types/conditional/conditionalTypes1.ts(24,5): error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'NonNullable[keyof T]>'. - Type 'undefined' is not assignable to type 'NonNullable[keyof T]>'. + Type 'undefined' is not assignable to type 'T[keyof T] & {}'. + Type 'undefined' is not assignable to type 'T[keyof T]'. tests/cases/conformance/types/conditional/conditionalTypes1.ts(29,5): error TS2322: Type 'T["x"]' is not assignable to type 'NonNullable'. Type 'string | undefined' is not assignable to type 'NonNullable'. Type 'undefined' is not assignable to type 'NonNullable'. + Type 'undefined' is not assignable to type '{}'. + Type 'T["x"]' is not assignable to type '{}'. + Type 'string | undefined' is not assignable to type '{}'. + Type 'undefined' is not assignable to type '{}'. tests/cases/conformance/types/conditional/conditionalTypes1.ts(103,5): error TS2322: Type 'FunctionProperties' is not assignable to type 'T'. 'T' could be instantiated with an arbitrary type which could be unrelated to 'FunctionProperties'. tests/cases/conformance/types/conditional/conditionalTypes1.ts(104,5): error TS2322: Type 'NonFunctionProperties' is not assignable to type 'T'. @@ -72,6 +83,8 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS y = x; // Error ~ !!! error TS2322: Type 'T' is not assignable to type 'NonNullable'. +!!! error TS2322: Type 'T' is not assignable to type '{}'. +!!! related TS2208 tests/cases/conformance/types/conditional/conditionalTypes1.ts:10:13: This type parameter probably needs an `extends object` constraint. } function f2(x: T, y: NonNullable) { @@ -81,6 +94,11 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS !!! error TS2322: Type 'T' is not assignable to type 'NonNullable'. !!! error TS2322: Type 'string | undefined' is not assignable to type 'NonNullable'. !!! error TS2322: Type 'undefined' is not assignable to type 'NonNullable'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T'. +!!! error TS2322: 'undefined' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string | undefined'. +!!! error TS2322: Type 'T' is not assignable to type '{}'. +!!! error TS2322: Type 'string | undefined' is not assignable to type '{}'. +!!! error TS2322: Type 'undefined' is not assignable to type '{}'. let s1: string = x; // Error let s2: string = y; } @@ -90,7 +108,8 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS y = x; // Error ~ !!! error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'NonNullable[keyof T]>'. -!!! error TS2322: Type 'undefined' is not assignable to type 'NonNullable[keyof T]>'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T] & {}'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T]'. } function f4(x: T["x"], y: NonNullable) { @@ -100,6 +119,10 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS !!! error TS2322: Type 'T["x"]' is not assignable to type 'NonNullable'. !!! error TS2322: Type 'string | undefined' is not assignable to type 'NonNullable'. !!! error TS2322: Type 'undefined' is not assignable to type 'NonNullable'. +!!! error TS2322: Type 'undefined' is not assignable to type '{}'. +!!! error TS2322: Type 'T["x"]' is not assignable to type '{}'. +!!! error TS2322: Type 'string | undefined' is not assignable to type '{}'. +!!! error TS2322: Type 'undefined' is not assignable to type '{}'. let s1: string = x; // Error let s2: string = y; } diff --git a/tests/baselines/reference/conditionalTypes1.types b/tests/baselines/reference/conditionalTypes1.types index 27b295caa8b..ec81f4b151f 100644 --- a/tests/baselines/reference/conditionalTypes1.types +++ b/tests/baselines/reference/conditionalTypes1.types @@ -55,7 +55,7 @@ function f2(x: T, y: NonNullable) { let s2: string = y; >s2 : string ->y : NonNullable +>y : string } function f3(x: Partial[keyof T], y: NonNullable[keyof T]>) { @@ -96,7 +96,7 @@ function f4(x: T["x"], y: NonNullables2 : string ->y : NonNullable +>y : string } type Options = { k: "a", a: number } | { k: "b", b: string } | { k: "c", c: boolean }; diff --git a/tests/baselines/reference/conditionalTypes2.errors.txt b/tests/baselines/reference/conditionalTypes2.errors.txt index 7a4f8bf7344..673156cf50e 100644 --- a/tests/baselines/reference/conditionalTypes2.errors.txt +++ b/tests/baselines/reference/conditionalTypes2.errors.txt @@ -32,7 +32,7 @@ tests/cases/conformance/types/conditional/conditionalTypes2.ts(74,12): error TS2 Property 'bat' is missing in type 'Foo & Bar' but required in type '{ foo: string; bat: string; }'. tests/cases/conformance/types/conditional/conditionalTypes2.ts(75,12): error TS2345: Argument of type 'Extract2' is not assignable to parameter of type '{ foo: string; bat: string; }'. Type 'T extends Bar ? T : never' is not assignable to type '{ foo: string; bat: string; }'. - Property 'bat' is missing in type 'Bar & Foo' but required in type '{ foo: string; bat: string; }'. + Type 'Bar & Foo & T' is not assignable to type '{ foo: string; bat: string; }'. ==== tests/cases/conformance/types/conditional/conditionalTypes2.ts (7 errors) ==== @@ -155,8 +155,7 @@ tests/cases/conformance/types/conditional/conditionalTypes2.ts(75,12): error TS2 ~ !!! error TS2345: Argument of type 'Extract2' is not assignable to parameter of type '{ foo: string; bat: string; }'. !!! error TS2345: Type 'T extends Bar ? T : never' is not assignable to type '{ foo: string; bat: string; }'. -!!! error TS2345: Property 'bat' is missing in type 'Bar & Foo' but required in type '{ foo: string; bat: string; }'. -!!! related TS2728 tests/cases/conformance/types/conditional/conditionalTypes2.ts:62:43: 'bat' is declared here. +!!! error TS2345: Type 'Bar & Foo & T' is not assignable to type '{ foo: string; bat: string; }'. } // Repros from #22860 diff --git a/tests/baselines/reference/controlFlowGenericTypes.types b/tests/baselines/reference/controlFlowGenericTypes.types index fc502a7dede..e6ebd4226b7 100644 --- a/tests/baselines/reference/controlFlowGenericTypes.types +++ b/tests/baselines/reference/controlFlowGenericTypes.types @@ -10,7 +10,7 @@ function f1(x: T, y: { a: T }, z: [T]): string { >x : T x; ->x : T +>x : NonNullable x.length; >x.length : number @@ -67,7 +67,7 @@ function f2(x: Extract | null): string { >x : Extract | null x; ->x : Extract +>x : NonNullable> x.length; >x.length : number @@ -404,11 +404,11 @@ function fx1(obj: T, key: K) { >key : K const x2 = obj && obj[key]; ->x2 : T[K] ->obj && obj[key] : T[K] ->obj : T ->obj[key] : T[K] +>x2 : NonNullable[K] +>obj && obj[key] : NonNullable[K] >obj : T +>obj[key] : NonNullable[K] +>obj : NonNullable >key : K } @@ -438,8 +438,8 @@ function fx3 | undefined, K extends keyof T>(o >key : K const x1 = obj[key]; // Error ->x1 : NonNullable>[K] ->obj[key] : NonNullable>[K] +>x1 : Record[K] +>obj[key] : Record[K] >obj : Record | undefined >key : K @@ -469,14 +469,14 @@ class TableBaseEnum< >null : null iSpec[null! as keyof InternalSpec]; // Error, object possibly undefined ->iSpec[null! as keyof InternalSpec] : NonNullable>[keyof InternalSpec] +>iSpec[null! as keyof InternalSpec] : Record[keyof InternalSpec] >iSpec : Record | undefined >null! as keyof InternalSpec : keyof InternalSpec >null! : never >null : null iSpec[null! as keyof PublicSpec]; // Error, object possibly undefined ->iSpec[null! as keyof PublicSpec] : NonNullable>[keyof PublicSpec] +>iSpec[null! as keyof PublicSpec] : Record[keyof PublicSpec] >iSpec : Record | undefined >null! as keyof PublicSpec : keyof PublicSpec >null! : never diff --git a/tests/baselines/reference/controlFlowTruthiness.types b/tests/baselines/reference/controlFlowTruthiness.types index 17f497267ee..f17f51958c8 100644 --- a/tests/baselines/reference/controlFlowTruthiness.types +++ b/tests/baselines/reference/controlFlowTruthiness.types @@ -181,7 +181,7 @@ function f8(x: T) { >x : T x; // {} ->x : T +>x : NonNullable } else { x; // {} diff --git a/tests/baselines/reference/controlFlowTypeofObject.types b/tests/baselines/reference/controlFlowTypeofObject.types index 68d99e6f0c2..fbd81cc8024 100644 --- a/tests/baselines/reference/controlFlowTypeofObject.types +++ b/tests/baselines/reference/controlFlowTypeofObject.types @@ -16,7 +16,7 @@ function f1(x: unknown) { if (typeof x === 'object') { >typeof x === 'object' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} >'object' : "object" obj(x); @@ -40,7 +40,7 @@ function f2(x: unknown) { if (typeof x === 'object') { >typeof x === 'object' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} | undefined >'object' : "object" obj(x); @@ -64,7 +64,7 @@ function f3(x: unknown) { if (typeof x === 'object') { >typeof x === 'object' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} >'object' : "object" obj(x); @@ -88,7 +88,7 @@ function f4(x: unknown) { if (typeof x === 'object') { >typeof x === 'object' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} >'object' : "object" obj(x); @@ -126,7 +126,7 @@ function f5(x: unknown) { if (typeof x === 'object') { >typeof x === 'object' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} | undefined >'object' : "object" obj(x); @@ -150,12 +150,12 @@ function f6(x: unknown) { } else { x; ->x : unknown +>x : {} | undefined if (typeof x === 'object') { >typeof x === 'object' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} | undefined >'object' : "object" obj(x); diff --git a/tests/baselines/reference/declarationEmitMappedTypeTemplateTypeofSymbol.errors.txt b/tests/baselines/reference/declarationEmitMappedTypeTemplateTypeofSymbol.errors.txt new file mode 100644 index 00000000000..769d1ff9d26 --- /dev/null +++ b/tests/baselines/reference/declarationEmitMappedTypeTemplateTypeofSymbol.errors.txt @@ -0,0 +1,25 @@ +tests/cases/compiler/b.ts(2,14): error TS4118: The type of this node cannot be serialized because its property '[timestampSymbol]' cannot be serialized. +tests/cases/compiler/c.ts(3,14): error TS4118: The type of this node cannot be serialized because its property '[timestampSymbol]' cannot be serialized. + + +==== tests/cases/compiler/a.d.ts (0 errors) ==== + export declare const timestampSymbol: unique symbol; + + export declare const Timestamp: { + [TKey in typeof timestampSymbol]: true; + }; + + export declare function now(): typeof Timestamp; + +==== tests/cases/compiler/b.ts (1 errors) ==== + import * as x from "./a"; + export const timestamp = x.now(); + ~~~~~~~~~ +!!! error TS4118: The type of this node cannot be serialized because its property '[timestampSymbol]' cannot be serialized. + +==== tests/cases/compiler/c.ts (1 errors) ==== + import { now } from "./a"; + + export const timestamp = now(); + ~~~~~~~~~ +!!! error TS4118: The type of this node cannot be serialized because its property '[timestampSymbol]' cannot be serialized. \ No newline at end of file diff --git a/tests/baselines/reference/declarationEmitMappedTypeTemplateTypeofSymbol.js b/tests/baselines/reference/declarationEmitMappedTypeTemplateTypeofSymbol.js new file mode 100644 index 00000000000..981d93fc222 --- /dev/null +++ b/tests/baselines/reference/declarationEmitMappedTypeTemplateTypeofSymbol.js @@ -0,0 +1,32 @@ +//// [tests/cases/compiler/declarationEmitMappedTypeTemplateTypeofSymbol.ts] //// + +//// [a.d.ts] +export declare const timestampSymbol: unique symbol; + +export declare const Timestamp: { + [TKey in typeof timestampSymbol]: true; +}; + +export declare function now(): typeof Timestamp; + +//// [b.ts] +import * as x from "./a"; +export const timestamp = x.now(); + +//// [c.ts] +import { now } from "./a"; + +export const timestamp = now(); + +//// [b.js] +"use strict"; +exports.__esModule = true; +exports.timestamp = void 0; +var x = require("./a"); +exports.timestamp = x.now(); +//// [c.js] +"use strict"; +exports.__esModule = true; +exports.timestamp = void 0; +var a_1 = require("./a"); +exports.timestamp = (0, a_1.now)(); diff --git a/tests/baselines/reference/declarationEmitMappedTypeTemplateTypeofSymbol.symbols b/tests/baselines/reference/declarationEmitMappedTypeTemplateTypeofSymbol.symbols new file mode 100644 index 00000000000..ba9ba5dec42 --- /dev/null +++ b/tests/baselines/reference/declarationEmitMappedTypeTemplateTypeofSymbol.symbols @@ -0,0 +1,35 @@ +=== tests/cases/compiler/a.d.ts === +export declare const timestampSymbol: unique symbol; +>timestampSymbol : Symbol(timestampSymbol, Decl(a.d.ts, 0, 20)) + +export declare const Timestamp: { +>Timestamp : Symbol(Timestamp, Decl(a.d.ts, 2, 20)) + + [TKey in typeof timestampSymbol]: true; +>TKey : Symbol(TKey, Decl(a.d.ts, 3, 5)) +>timestampSymbol : Symbol(timestampSymbol, Decl(a.d.ts, 0, 20)) + +}; + +export declare function now(): typeof Timestamp; +>now : Symbol(now, Decl(a.d.ts, 4, 2)) +>Timestamp : Symbol(Timestamp, Decl(a.d.ts, 2, 20)) + +=== tests/cases/compiler/b.ts === +import * as x from "./a"; +>x : Symbol(x, Decl(b.ts, 0, 6)) + +export const timestamp = x.now(); +>timestamp : Symbol(timestamp, Decl(b.ts, 1, 12)) +>x.now : Symbol(x.now, Decl(a.d.ts, 4, 2)) +>x : Symbol(x, Decl(b.ts, 0, 6)) +>now : Symbol(x.now, Decl(a.d.ts, 4, 2)) + +=== tests/cases/compiler/c.ts === +import { now } from "./a"; +>now : Symbol(now, Decl(c.ts, 0, 8)) + +export const timestamp = now(); +>timestamp : Symbol(timestamp, Decl(c.ts, 2, 12)) +>now : Symbol(now, Decl(c.ts, 0, 8)) + diff --git a/tests/baselines/reference/declarationEmitMappedTypeTemplateTypeofSymbol.types b/tests/baselines/reference/declarationEmitMappedTypeTemplateTypeofSymbol.types new file mode 100644 index 00000000000..caaced753ee --- /dev/null +++ b/tests/baselines/reference/declarationEmitMappedTypeTemplateTypeofSymbol.types @@ -0,0 +1,37 @@ +=== tests/cases/compiler/a.d.ts === +export declare const timestampSymbol: unique symbol; +>timestampSymbol : unique symbol + +export declare const Timestamp: { +>Timestamp : { [timestampSymbol]: true; } + + [TKey in typeof timestampSymbol]: true; +>timestampSymbol : unique symbol +>true : true + +}; + +export declare function now(): typeof Timestamp; +>now : () => typeof Timestamp +>Timestamp : { [timestampSymbol]: true; } + +=== tests/cases/compiler/b.ts === +import * as x from "./a"; +>x : typeof x + +export const timestamp = x.now(); +>timestamp : { [x.timestampSymbol]: true; } +>x.now() : { [x.timestampSymbol]: true; } +>x.now : () => { [x.timestampSymbol]: true; } +>x : typeof x +>now : () => { [x.timestampSymbol]: true; } + +=== tests/cases/compiler/c.ts === +import { now } from "./a"; +>now : () => { [timestampSymbol]: true; } + +export const timestamp = now(); +>timestamp : { [timestampSymbol]: true; } +>now() : { [timestampSymbol]: true; } +>now : () => { [timestampSymbol]: true; } + diff --git a/tests/baselines/reference/discriminatedUnionJsxElement.types b/tests/baselines/reference/discriminatedUnionJsxElement.types index 4f7b5a1ccdd..9057c9c55ab 100644 --- a/tests/baselines/reference/discriminatedUnionJsxElement.types +++ b/tests/baselines/reference/discriminatedUnionJsxElement.types @@ -14,8 +14,8 @@ function Menu >data : IData const listItemVariant = data.menuItemsVariant ?? ListItemVariant.OneLine; ->listItemVariant : ListItemVariant.OneLine | NonNullable ->data.menuItemsVariant ?? ListItemVariant.OneLine : ListItemVariant.OneLine | NonNullable +>listItemVariant : ListItemVariant.OneLine | MenuItemVariant +>data.menuItemsVariant ?? ListItemVariant.OneLine : ListItemVariant.OneLine | MenuItemVariant >data.menuItemsVariant : MenuItemVariant | undefined >data : IData >menuItemsVariant : MenuItemVariant | undefined diff --git a/tests/baselines/reference/errorLocationForInterfaceExtension.errors.txt b/tests/baselines/reference/errorLocationForInterfaceExtension.errors.txt index 6ed1517335d..24a6309e129 100644 --- a/tests/baselines/reference/errorLocationForInterfaceExtension.errors.txt +++ b/tests/baselines/reference/errorLocationForInterfaceExtension.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/errorLocationForInterfaceExtension.ts(3,21): error TS2693: 'string' only refers to a type, but is being used as a value here. +tests/cases/compiler/errorLocationForInterfaceExtension.ts(3,21): error TS2840: An interface cannot extend a primitive type like 'string'; an interface can only extend named types and classes ==== tests/cases/compiler/errorLocationForInterfaceExtension.ts (1 errors) ==== @@ -6,5 +6,5 @@ tests/cases/compiler/errorLocationForInterfaceExtension.ts(3,21): error TS2693: interface x extends string { } ~~~~~~ -!!! error TS2693: 'string' only refers to a type, but is being used as a value here. +!!! error TS2840: An interface cannot extend a primitive type like 'string'; an interface can only extend named types and classes \ No newline at end of file diff --git a/tests/baselines/reference/findAllRefsRootSymbols.baseline.jsonc b/tests/baselines/reference/findAllRefsRootSymbols.baseline.jsonc index e262c15548b..f8cf052e206 100644 --- a/tests/baselines/reference/findAllRefsRootSymbols.baseline.jsonc +++ b/tests/baselines/reference/findAllRefsRootSymbols.baseline.jsonc @@ -89,7 +89,7 @@ "containerName": "", "fileName": "/tests/cases/fourslash/findAllRefsRootSymbols.ts", "kind": "property", - "name": "(property) x: {} & string", + "name": "(property) x: string", "textSpan": { "start": 14, "length": 1 @@ -123,26 +123,6 @@ "text": " ", "kind": "space" }, - { - "text": "{", - "kind": "punctuation" - }, - { - "text": "}", - "kind": "punctuation" - }, - { - "text": " ", - "kind": "space" - }, - { - "text": "&", - "kind": "punctuation" - }, - { - "text": " ", - "kind": "space" - }, { "text": "string", "kind": "keyword" @@ -258,7 +238,7 @@ "containerName": "", "fileName": "/tests/cases/fourslash/findAllRefsRootSymbols.ts", "kind": "property", - "name": "(property) x: {} & string", + "name": "(property) x: string", "textSpan": { "start": 14, "length": 1 @@ -292,26 +272,6 @@ "text": " ", "kind": "space" }, - { - "text": "{", - "kind": "punctuation" - }, - { - "text": "}", - "kind": "punctuation" - }, - { - "text": " ", - "kind": "space" - }, - { - "text": "&", - "kind": "punctuation" - }, - { - "text": " ", - "kind": "space" - }, { "text": "string", "kind": "keyword" @@ -415,7 +375,7 @@ "containerName": "", "fileName": "/tests/cases/fourslash/findAllRefsRootSymbols.ts", "kind": "property", - "name": "(property) x: {} & string", + "name": "(property) x: string", "textSpan": { "start": 14, "length": 1 @@ -449,26 +409,6 @@ "text": " ", "kind": "space" }, - { - "text": "{", - "kind": "punctuation" - }, - { - "text": "}", - "kind": "punctuation" - }, - { - "text": " ", - "kind": "space" - }, - { - "text": "&", - "kind": "punctuation" - }, - { - "text": " ", - "kind": "space" - }, { "text": "string", "kind": "keyword" @@ -725,7 +665,7 @@ "containerName": "", "fileName": "/tests/cases/fourslash/findAllRefsRootSymbols.ts", "kind": "property", - "name": "(property) x: {} & string", + "name": "(property) x: string", "textSpan": { "start": 14, "length": 1 @@ -759,26 +699,6 @@ "text": " ", "kind": "space" }, - { - "text": "{", - "kind": "punctuation" - }, - { - "text": "}", - "kind": "punctuation" - }, - { - "text": " ", - "kind": "space" - }, - { - "text": "&", - "kind": "punctuation" - }, - { - "text": " ", - "kind": "space" - }, { "text": "string", "kind": "keyword" diff --git a/tests/baselines/reference/genericUnboundedTypeParamAssignability.errors.txt b/tests/baselines/reference/genericUnboundedTypeParamAssignability.errors.txt index b00dfc3c328..6d7b87ebd33 100644 --- a/tests/baselines/reference/genericUnboundedTypeParamAssignability.errors.txt +++ b/tests/baselines/reference/genericUnboundedTypeParamAssignability.errors.txt @@ -1,8 +1,10 @@ tests/cases/compiler/genericUnboundedTypeParamAssignability.ts(2,5): error TS2339: Property 'toString' does not exist on type 'T'. +tests/cases/compiler/genericUnboundedTypeParamAssignability.ts(15,6): error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. +tests/cases/compiler/genericUnboundedTypeParamAssignability.ts(16,6): error TS2345: Argument of type 'T' is not assignable to parameter of type 'Record'. tests/cases/compiler/genericUnboundedTypeParamAssignability.ts(17,5): error TS2339: Property 'toString' does not exist on type 'T'. -==== tests/cases/compiler/genericUnboundedTypeParamAssignability.ts (2 errors) ==== +==== tests/cases/compiler/genericUnboundedTypeParamAssignability.ts (4 errors) ==== function f1(o: T) { o.toString(); // error ~~~~~~~~ @@ -20,7 +22,13 @@ tests/cases/compiler/genericUnboundedTypeParamAssignability.ts(17,5): error TS23 function user(t: T) { f1(t); f2(t); // error in strict, unbounded T doesn't satisfy the constraint + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. +!!! related TS2208 tests/cases/compiler/genericUnboundedTypeParamAssignability.ts:13:15: This type parameter probably needs an `extends object` constraint. f3(t); // error in strict, unbounded T doesn't satisfy the constraint + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'Record'. +!!! related TS2208 tests/cases/compiler/genericUnboundedTypeParamAssignability.ts:13:15: This type parameter probably needs an `extends object` constraint. t.toString(); // error, for the same reason as f1() ~~~~~~~~ !!! error TS2339: Property 'toString' does not exist on type 'T'. diff --git a/tests/baselines/reference/inDoesNotOperateOnPrimitiveTypes.errors.txt b/tests/baselines/reference/inDoesNotOperateOnPrimitiveTypes.errors.txt index 90652969ed1..049b46621e8 100644 --- a/tests/baselines/reference/inDoesNotOperateOnPrimitiveTypes.errors.txt +++ b/tests/baselines/reference/inDoesNotOperateOnPrimitiveTypes.errors.txt @@ -3,12 +3,11 @@ tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(23,12): error TS2361: T tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(27,12): error TS2361: The right-hand side of an 'in' expression must not be a primitive. tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(34,12): error TS2361: The right-hand side of an 'in' expression must not be a primitive. tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(53,14): error TS2361: The right-hand side of an 'in' expression must not be a primitive. -tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(55,18): error TS2361: The right-hand side of an 'in' expression must not be a primitive. tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(60,12): error TS2361: The right-hand side of an 'in' expression must not be a primitive. tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(64,12): error TS2361: The right-hand side of an 'in' expression must not be a primitive. -==== tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts (8 errors) ==== +==== tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts (7 errors) ==== const validHasKey = ( thing: T, key: string, @@ -74,8 +73,6 @@ tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(64,12): error TS2361: T !!! error TS2361: The right-hand side of an 'in' expression must not be a primitive. if (typeof p === "object") { "key" in p; - ~ -!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive. } } diff --git a/tests/baselines/reference/inDoesNotOperateOnPrimitiveTypes.types b/tests/baselines/reference/inDoesNotOperateOnPrimitiveTypes.types index 9175fd9022f..f56bbf9395d 100644 --- a/tests/baselines/reference/inDoesNotOperateOnPrimitiveTypes.types +++ b/tests/baselines/reference/inDoesNotOperateOnPrimitiveTypes.types @@ -146,7 +146,7 @@ function union5(p: T | U) "key" in p; >"key" in p : boolean >"key" : "key" ->p : T | U +>p : (T & object) | (U & object) } } diff --git a/tests/baselines/reference/interfacedeclWithIndexerErrors.errors.txt b/tests/baselines/reference/interfacedeclWithIndexerErrors.errors.txt index 2939a04948a..6aebe8a31f1 100644 --- a/tests/baselines/reference/interfacedeclWithIndexerErrors.errors.txt +++ b/tests/baselines/reference/interfacedeclWithIndexerErrors.errors.txt @@ -3,9 +3,11 @@ tests/cases/compiler/interfacedeclWithIndexerErrors.ts(14,5): error TS2411: Prop tests/cases/compiler/interfacedeclWithIndexerErrors.ts(15,5): error TS2411: Property 'p5' of type '(s: number) => string' is not assignable to 'string' index type '() => string'. tests/cases/compiler/interfacedeclWithIndexerErrors.ts(19,5): error TS2411: Property 'f3' of type '(a: string) => number' is not assignable to 'string' index type '() => string'. tests/cases/compiler/interfacedeclWithIndexerErrors.ts(20,5): error TS2411: Property 'f4' of type '(s: number) => string' is not assignable to 'string' index type '() => string'. +tests/cases/compiler/interfacedeclWithIndexerErrors.ts(44,21): error TS2840: An interface cannot extend a primitive type like 'number'; an interface can only extend named types and classes +tests/cases/compiler/interfacedeclWithIndexerErrors.ts(48,18): error TS2693: 'string' only refers to a type, but is being used as a value here. -==== tests/cases/compiler/interfacedeclWithIndexerErrors.ts (5 errors) ==== +==== tests/cases/compiler/interfacedeclWithIndexerErrors.ts (7 errors) ==== interface a0 { (): string; (a, b, c?: string): number; @@ -59,6 +61,17 @@ tests/cases/compiler/interfacedeclWithIndexerErrors.ts(20,5): error TS2411: Prop interface d extends a { } + interface e extends number { + ~~~~~~ +!!! error TS2840: An interface cannot extend a primitive type like 'number'; an interface can only extend named types and classes + } + + interface f { + prop: typeof string; + ~~~~~~ +!!! error TS2693: 'string' only refers to a type, but is being used as a value here. + } + class c1 implements a { } var instance2 = new c1(); \ No newline at end of file diff --git a/tests/baselines/reference/interfacedeclWithIndexerErrors.js b/tests/baselines/reference/interfacedeclWithIndexerErrors.js index 776d43b940d..599ac30590a 100644 --- a/tests/baselines/reference/interfacedeclWithIndexerErrors.js +++ b/tests/baselines/reference/interfacedeclWithIndexerErrors.js @@ -42,6 +42,13 @@ interface c extends a, b { interface d extends a { } +interface e extends number { +} + +interface f { + prop: typeof string; +} + class c1 implements a { } var instance2 = new c1(); diff --git a/tests/baselines/reference/interfacedeclWithIndexerErrors.symbols b/tests/baselines/reference/interfacedeclWithIndexerErrors.symbols index 32880f2cb91..1ae6cf85950 100644 --- a/tests/baselines/reference/interfacedeclWithIndexerErrors.symbols +++ b/tests/baselines/reference/interfacedeclWithIndexerErrors.symbols @@ -84,11 +84,22 @@ interface d extends a { >a : Symbol(a, Decl(interfacedeclWithIndexerErrors.ts, 29, 1)) } +interface e extends number { +>e : Symbol(e, Decl(interfacedeclWithIndexerErrors.ts, 41, 1)) +} + +interface f { +>f : Symbol(f, Decl(interfacedeclWithIndexerErrors.ts, 44, 1)) + + prop: typeof string; +>prop : Symbol(f.prop, Decl(interfacedeclWithIndexerErrors.ts, 46, 13)) +} + class c1 implements a { ->c1 : Symbol(c1, Decl(interfacedeclWithIndexerErrors.ts, 41, 1)) +>c1 : Symbol(c1, Decl(interfacedeclWithIndexerErrors.ts, 48, 1)) >a : Symbol(a, Decl(interfacedeclWithIndexerErrors.ts, 29, 1)) } var instance2 = new c1(); ->instance2 : Symbol(instance2, Decl(interfacedeclWithIndexerErrors.ts, 45, 3)) ->c1 : Symbol(c1, Decl(interfacedeclWithIndexerErrors.ts, 41, 1)) +>instance2 : Symbol(instance2, Decl(interfacedeclWithIndexerErrors.ts, 52, 3)) +>c1 : Symbol(c1, Decl(interfacedeclWithIndexerErrors.ts, 48, 1)) diff --git a/tests/baselines/reference/interfacedeclWithIndexerErrors.types b/tests/baselines/reference/interfacedeclWithIndexerErrors.types index 67259ae88b8..a2f9964449d 100644 --- a/tests/baselines/reference/interfacedeclWithIndexerErrors.types +++ b/tests/baselines/reference/interfacedeclWithIndexerErrors.types @@ -70,6 +70,15 @@ interface c extends a, b { interface d extends a { } +interface e extends number { +} + +interface f { + prop: typeof string; +>prop : any +>string : any +} + class c1 implements a { >c1 : c1 } diff --git a/tests/baselines/reference/intersectionReduction.types b/tests/baselines/reference/intersectionReduction.types index 4ecfe50e427..fc04d01441c 100644 --- a/tests/baselines/reference/intersectionReduction.types +++ b/tests/baselines/reference/intersectionReduction.types @@ -346,7 +346,7 @@ function inGeneric(alsoShouldBeB: T & B2) { const b: B2 = alsoShouldBeB; >b : B2 ->alsoShouldBeB : T & B2 +>alsoShouldBeB : B2 } // Repro from #38542 @@ -374,6 +374,6 @@ function bar(x: T & CA) { let ab: ABI = x; >ab : ABI ->x : T & CA +>x : CA } diff --git a/tests/baselines/reference/intersectionWithUnionConstraint.errors.txt b/tests/baselines/reference/intersectionWithUnionConstraint.errors.txt index 0dd473a4f4a..2a4ee7b3a37 100644 --- a/tests/baselines/reference/intersectionWithUnionConstraint.errors.txt +++ b/tests/baselines/reference/intersectionWithUnionConstraint.errors.txt @@ -1,8 +1,13 @@ -tests/cases/conformance/types/intersection/intersectionWithUnionConstraint.ts(7,9): error TS2322: Type 'T & U' is not assignable to type 'string | number'. -tests/cases/conformance/types/intersection/intersectionWithUnionConstraint.ts(8,9): error TS2322: Type 'T & U' is not assignable to type 'string | null'. -tests/cases/conformance/types/intersection/intersectionWithUnionConstraint.ts(10,9): error TS2322: Type 'T & U' is not assignable to type 'number | null'. -tests/cases/conformance/types/intersection/intersectionWithUnionConstraint.ts(11,9): error TS2322: Type 'T & U' is not assignable to type 'number | undefined'. -tests/cases/conformance/types/intersection/intersectionWithUnionConstraint.ts(12,9): error TS2322: Type 'T & U' is not assignable to type 'null | undefined'. +tests/cases/conformance/types/intersection/intersectionWithUnionConstraint.ts(7,9): error TS2322: Type 'string | undefined' is not assignable to type 'string | number'. + Type 'undefined' is not assignable to type 'string | number'. +tests/cases/conformance/types/intersection/intersectionWithUnionConstraint.ts(8,9): error TS2322: Type 'string | undefined' is not assignable to type 'string | null'. + Type 'undefined' is not assignable to type 'string | null'. +tests/cases/conformance/types/intersection/intersectionWithUnionConstraint.ts(10,9): error TS2322: Type 'string | undefined' is not assignable to type 'number | null'. + Type 'undefined' is not assignable to type 'number | null'. +tests/cases/conformance/types/intersection/intersectionWithUnionConstraint.ts(11,9): error TS2322: Type 'string | undefined' is not assignable to type 'number | undefined'. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/types/intersection/intersectionWithUnionConstraint.ts(12,9): error TS2322: Type 'string | undefined' is not assignable to type 'null | undefined'. + Type 'string' is not assignable to type 'null | undefined'. ==== tests/cases/conformance/types/intersection/intersectionWithUnionConstraint.ts (5 errors) ==== @@ -14,20 +19,25 @@ tests/cases/conformance/types/intersection/intersectionWithUnionConstraint.ts(12 function f2(x: T & U) { let y1: string | number = x; // Error ~~ -!!! error TS2322: Type 'T & U' is not assignable to type 'string | number'. +!!! error TS2322: Type 'string | undefined' is not assignable to type 'string | number'. +!!! error TS2322: Type 'undefined' is not assignable to type 'string | number'. let y2: string | null = x; // Error ~~ -!!! error TS2322: Type 'T & U' is not assignable to type 'string | null'. +!!! error TS2322: Type 'string | undefined' is not assignable to type 'string | null'. +!!! error TS2322: Type 'undefined' is not assignable to type 'string | null'. let y3: string | undefined = x; let y4: number | null = x; // Error ~~ -!!! error TS2322: Type 'T & U' is not assignable to type 'number | null'. +!!! error TS2322: Type 'string | undefined' is not assignable to type 'number | null'. +!!! error TS2322: Type 'undefined' is not assignable to type 'number | null'. let y5: number | undefined = x; // Error ~~ -!!! error TS2322: Type 'T & U' is not assignable to type 'number | undefined'. +!!! error TS2322: Type 'string | undefined' is not assignable to type 'number | undefined'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. let y6: null | undefined = x; // Error ~~ -!!! error TS2322: Type 'T & U' is not assignable to type 'null | undefined'. +!!! error TS2322: Type 'string | undefined' is not assignable to type 'null | undefined'. +!!! error TS2322: Type 'string' is not assignable to type 'null | undefined'. } type T1 = (string | number | undefined) & (string | null | undefined); // string | undefined diff --git a/tests/baselines/reference/intersectionWithUnionConstraint.types b/tests/baselines/reference/intersectionWithUnionConstraint.types index ba079e2bf81..5b530f76f46 100644 --- a/tests/baselines/reference/intersectionWithUnionConstraint.types +++ b/tests/baselines/reference/intersectionWithUnionConstraint.types @@ -6,7 +6,7 @@ function f1(x: T & U) { // Combined constraint of 'T & U' is 'string | number' let y: string | number = x; >y : string | number ->x : T & U +>x : string | number } function f2(x: T & U) { @@ -16,30 +16,30 @@ function f2y1 : string | number ->x : T & U +>x : string | undefined let y2: string | null = x; // Error >y2 : string | null >null : null ->x : T & U +>x : string | undefined let y3: string | undefined = x; >y3 : string | undefined ->x : T & U +>x : string | undefined let y4: number | null = x; // Error >y4 : number | null >null : null ->x : T & U +>x : string | undefined let y5: number | undefined = x; // Error >y5 : number | undefined ->x : T & U +>x : string | undefined let y6: null | undefined = x; // Error >y6 : null | undefined >null : null ->x : T & U +>x : string | undefined } type T1 = (string | number | undefined) & (string | null | undefined); // string | undefined @@ -52,7 +52,7 @@ function f3(x: T & (number | object | und const y: number | undefined = x; >y : number | undefined ->x : T & (number | object | undefined) +>x : number | undefined } function f4(x: T & (number | object)) { @@ -61,7 +61,7 @@ function f4(x: T & (number | object)) { const y: number = x; >y : number ->x : T & (number | object) +>x : number } function f5(x: keyof T & U) { @@ -70,7 +70,7 @@ function f5(x: keyof T & U) { let y: keyof any = x; >y : string | number | symbol ->x : keyof T & U +>x : string | number | symbol } // Repro from #23648 diff --git a/tests/baselines/reference/intersectionsAndEmptyObjects.types b/tests/baselines/reference/intersectionsAndEmptyObjects.types index 5459f614a89..6972e06169d 100644 --- a/tests/baselines/reference/intersectionsAndEmptyObjects.types +++ b/tests/baselines/reference/intersectionsAndEmptyObjects.types @@ -26,10 +26,10 @@ let x04: A & B & C; >x04 : A & B let x05: string & C; ->x05 : string & C +>x05 : string let x06: C & string; ->x06 : C & string +>x06 : string let x07: C; >x07 : C diff --git a/tests/baselines/reference/keyofAndIndexedAccess.errors.txt b/tests/baselines/reference/keyofAndIndexedAccess.errors.txt new file mode 100644 index 00000000000..97bad1c12f5 --- /dev/null +++ b/tests/baselines/reference/keyofAndIndexedAccess.errors.txt @@ -0,0 +1,677 @@ +tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(316,5): error TS2322: Type 'T' is not assignable to type '{}'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(317,5): error TS2322: Type 'T[keyof T]' is not assignable to type '{}'. + Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{}'. + Type 'T[string]' is not assignable to type '{}'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(318,5): error TS2322: Type 'T[K]' is not assignable to type '{}'. + Type 'T[keyof T]' is not assignable to type '{}'. + + +==== tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts (3 errors) ==== + class Shape { + name: string; + width: number; + height: number; + visible: boolean; + } + + class TaggedShape extends Shape { + tag: string; + } + + class Item { + name: string; + price: number; + } + + class Options { + visible: "yes" | "no"; + } + + type Dictionary = { [x: string]: T }; + type NumericallyIndexed = { [x: number]: T }; + + const enum E { A, B, C } + + type K00 = keyof any; // string + type K01 = keyof string; // "toString" | "charAt" | ... + type K02 = keyof number; // "toString" | "toFixed" | "toExponential" | ... + type K03 = keyof boolean; // "valueOf" + type K04 = keyof void; // never + type K05 = keyof undefined; // never + type K06 = keyof null; // never + type K07 = keyof never; // string | number | symbol + type K08 = keyof unknown; // never + + type K10 = keyof Shape; // "name" | "width" | "height" | "visible" + type K11 = keyof Shape[]; // "length" | "toString" | ... + type K12 = keyof Dictionary; // string + type K13 = keyof {}; // never + type K14 = keyof Object; // "constructor" | "toString" | ... + type K15 = keyof E; // "toString" | "toFixed" | "toExponential" | ... + type K16 = keyof [string, number]; // "0" | "1" | "length" | "toString" | ... + type K17 = keyof (Shape | Item); // "name" + type K18 = keyof (Shape & Item); // "name" | "width" | "height" | "visible" | "price" + type K19 = keyof NumericallyIndexed // never + + type KeyOf = keyof T; + + type K20 = KeyOf; // "name" | "width" | "height" | "visible" + type K21 = KeyOf>; // string + + type NAME = "name"; + type WIDTH_OR_HEIGHT = "width" | "height"; + + type Q10 = Shape["name"]; // string + type Q11 = Shape["width" | "height"]; // number + type Q12 = Shape["name" | "visible"]; // string | boolean + + type Q20 = Shape[NAME]; // string + type Q21 = Shape[WIDTH_OR_HEIGHT]; // number + + type Q30 = [string, number][0]; // string + type Q31 = [string, number][1]; // number + type Q32 = [string, number][number]; // string | number + type Q33 = [string, number][E.A]; // string + type Q34 = [string, number][E.B]; // number + type Q35 = [string, number]["0"]; // string + type Q36 = [string, number]["1"]; // string + + type Q40 = (Shape | Options)["visible"]; // boolean | "yes" | "no" + type Q41 = (Shape & Options)["visible"]; // true & "yes" | true & "no" | false & "yes" | false & "no" + + type Q50 = Dictionary["howdy"]; // Shape + type Q51 = Dictionary[123]; // Shape + type Q52 = Dictionary[E.B]; // Shape + + declare let cond: boolean; + + function getProperty(obj: T, key: K) { + return obj[key]; + } + + function setProperty(obj: T, key: K, value: T[K]) { + obj[key] = value; + } + + function f10(shape: Shape) { + let name = getProperty(shape, "name"); // string + let widthOrHeight = getProperty(shape, cond ? "width" : "height"); // number + let nameOrVisible = getProperty(shape, cond ? "name" : "visible"); // string | boolean + setProperty(shape, "name", "rectangle"); + setProperty(shape, cond ? "width" : "height", 10); + setProperty(shape, cond ? "name" : "visible", true); // Technically not safe + } + + function f11(a: Shape[]) { + let len = getProperty(a, "length"); // number + setProperty(a, "length", len); + } + + function f12(t: [Shape, boolean]) { + let len = getProperty(t, "length"); + let s2 = getProperty(t, "0"); // Shape + let b2 = getProperty(t, "1"); // boolean + } + + function f13(foo: any, bar: any) { + let x = getProperty(foo, "x"); // any + let y = getProperty(foo, "100"); // any + let z = getProperty(foo, bar); // any + } + + class Component { + props: PropType; + getProperty(key: K) { + return this.props[key]; + } + setProperty(key: K, value: PropType[K]) { + this.props[key] = value; + } + } + + function f20(component: Component) { + let name = component.getProperty("name"); // string + let widthOrHeight = component.getProperty(cond ? "width" : "height"); // number + let nameOrVisible = component.getProperty(cond ? "name" : "visible"); // string | boolean + component.setProperty("name", "rectangle"); + component.setProperty(cond ? "width" : "height", 10) + component.setProperty(cond ? "name" : "visible", true); // Technically not safe + } + + function pluck(array: T[], key: K) { + return array.map(x => x[key]); + } + + function f30(shapes: Shape[]) { + let names = pluck(shapes, "name"); // string[] + let widths = pluck(shapes, "width"); // number[] + let nameOrVisibles = pluck(shapes, cond ? "name" : "visible"); // (string | boolean)[] + } + + function f31(key: K) { + const shape: Shape = { name: "foo", width: 5, height: 10, visible: true }; + return shape[key]; // Shape[K] + } + + function f32(key: K) { + const shape: Shape = { name: "foo", width: 5, height: 10, visible: true }; + return shape[key]; // Shape[K] + } + + function f33(shape: S, key: K) { + let name = getProperty(shape, "name"); + let prop = getProperty(shape, key); + return prop; + } + + function f34(ts: TaggedShape) { + let tag1 = f33(ts, "tag"); + let tag2 = getProperty(ts, "tag"); + } + + class C { + public x: string; + protected y: string; + private z: string; + } + + // Indexed access expressions have always permitted access to private and protected members. + // For consistency we also permit such access in indexed access types. + function f40(c: C) { + type X = C["x"]; + type Y = C["y"]; + type Z = C["z"]; + let x: X = c["x"]; + let y: Y = c["y"]; + let z: Z = c["z"]; + } + + function f50(k: keyof T, s: string) { + const x1 = s as keyof T; + const x2 = k as string; + } + + function f51(k: K, s: string) { + const x1 = s as keyof T; + const x2 = k as string; + } + + function f52(obj: { [x: string]: boolean }, k: Exclude, s: string, n: number) { + const x1 = obj[s]; + const x2 = obj[n]; + const x3 = obj[k]; + } + + function f53>(obj: { [x: string]: boolean }, k: K, s: string, n: number) { + const x1 = obj[s]; + const x2 = obj[n]; + const x3 = obj[k]; + } + + function f54(obj: T, key: keyof T) { + for (let s in obj[key]) { + } + const b = "foo" in obj[key]; + } + + function f55(obj: T, key: K) { + for (let s in obj[key]) { + } + const b = "foo" in obj[key]; + } + + function f60(source: T, target: T) { + for (let k in source) { + target[k] = source[k]; + } + } + + function f70(func: (k1: keyof (T | U), k2: keyof (T & U)) => void) { + func<{ a: any, b: any }, { a: any, c: any }>('a', 'a'); + func<{ a: any, b: any }, { a: any, c: any }>('a', 'b'); + func<{ a: any, b: any }, { a: any, c: any }>('a', 'c'); + } + + function f71(func: (x: T, y: U) => Partial) { + let x = func({ a: 1, b: "hello" }, { c: true }); + x.a; // number | undefined + x.b; // string | undefined + x.c; // boolean | undefined + } + + function f72(func: (x: T, y: U, k: K) => (T & U)[K]) { + let a = func({ a: 1, b: "hello" }, { c: true }, 'a'); // number + let b = func({ a: 1, b: "hello" }, { c: true }, 'b'); // string + let c = func({ a: 1, b: "hello" }, { c: true }, 'c'); // boolean + } + + function f73(func: (x: T, y: U, k: K) => (T & U)[K]) { + let a = func({ a: 1, b: "hello" }, { c: true }, 'a'); // number + let b = func({ a: 1, b: "hello" }, { c: true }, 'b'); // string + let c = func({ a: 1, b: "hello" }, { c: true }, 'c'); // boolean + } + + function f74(func: (x: T, y: U, k: K) => (T | U)[K]) { + let a = func({ a: 1, b: "hello" }, { a: 2, b: true }, 'a'); // number + let b = func({ a: 1, b: "hello" }, { a: 2, b: true }, 'b'); // string | boolean + } + + function f80(obj: T) { + let a1 = obj.a; // { x: any } + let a2 = obj['a']; // { x: any } + let a3 = obj['a'] as T['a']; // T["a"] + let x1 = obj.a.x; // any + let x2 = obj['a']['x']; // any + let x3 = obj['a']['x'] as T['a']['x']; // T["a"]["x"] + } + + function f81(obj: T) { + return obj['a']['x'] as T['a']['x']; + } + + function f82() { + let x1 = f81({ a: { x: "hello" } }); // string + let x2 = f81({ a: { x: 42 } }); // number + } + + function f83(obj: T, key: K) { + return obj[key]['x'] as T[K]['x']; + } + + function f84() { + let x1 = f83({ foo: { x: "hello" } }, "foo"); // string + let x2 = f83({ bar: { x: 42 } }, "bar"); // number + } + + class C1 { + x: number; + get(key: K) { + return this[key]; + } + set(key: K, value: this[K]) { + this[key] = value; + } + foo() { + let x1 = this.x; // number + let x2 = this["x"]; // number + let x3 = this.get("x"); // this["x"] + let x4 = getProperty(this, "x"); // this["x"] + this.x = 42; + this["x"] = 42; + this.set("x", 42); + setProperty(this, "x", 42); + } + } + + type S2 = { + a: string; + b: string; + }; + + function f90(x1: S2[keyof S2], x2: T[keyof S2], x3: S2[K]) { + x1 = x2; + x1 = x3; + x2 = x1; + x2 = x3; + x3 = x1; + x3 = x2; + x1.length; + x2.length; + x3.length; + } + + function f91(x: T, y: T[keyof T], z: T[K]) { + let a: {}; + a = x; + ~ +!!! error TS2322: Type 'T' is not assignable to type '{}'. +!!! related TS2208 tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts:314:14: This type parameter probably needs an `extends object` constraint. + a = y; + ~ +!!! error TS2322: Type 'T[keyof T]' is not assignable to type '{}'. +!!! error TS2322: Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{}'. +!!! error TS2322: Type 'T[string]' is not assignable to type '{}'. + a = z; + ~ +!!! error TS2322: Type 'T[K]' is not assignable to type '{}'. +!!! error TS2322: Type 'T[keyof T]' is not assignable to type '{}'. + } + + function f92(x: T, y: T[keyof T], z: T[K]) { + let a: {} | null | undefined; + a = x; + a = y; + a = z; + } + + // Repros from #12011 + + class Base { + get(prop: K) { + return this[prop]; + } + set(prop: K, value: this[K]) { + this[prop] = value; + } + } + + class Person extends Base { + parts: number; + constructor(parts: number) { + super(); + this.set("parts", parts); + } + getParts() { + return this.get("parts") + } + } + + class OtherPerson { + parts: number; + constructor(parts: number) { + setProperty(this, "parts", parts); + } + getParts() { + return getProperty(this, "parts") + } + } + + // Modified repro from #12544 + + function path(obj: T, key1: K1): T[K1]; + function path(obj: T, key1: K1, key2: K2): T[K1][K2]; + function path(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; + function path(obj: any, ...keys: (string | number)[]): any; + function path(obj: any, ...keys: (string | number)[]): any { + let result = obj; + for (let k of keys) { + result = result[k]; + } + return result; + } + + type Thing = { + a: { x: number, y: string }, + b: boolean + }; + + + function f1(thing: Thing) { + let x1 = path(thing, 'a'); // { x: number, y: string } + let x2 = path(thing, 'a', 'y'); // string + let x3 = path(thing, 'b'); // boolean + let x4 = path(thing, ...['a', 'x']); // any + } + + // Repro from comment in #12114 + + const assignTo2 = (object: T, key1: K1, key2: K2) => + (value: T[K1][K2]) => object[key1][key2] = value; + + // Modified repro from #12573 + + declare function one(handler: (t: T) => void): T + var empty = one(() => {}) // inferred as {}, expected + + type Handlers = { [K in keyof T]: (t: T[K]) => void } + declare function on(handlerHash: Handlers): T + var hashOfEmpty1 = on({ test: () => {} }); // {} + var hashOfEmpty2 = on({ test: (x: boolean) => {} }); // { test: boolean } + + // Repro from #12624 + + interface Options1 { + data?: Data + computed?: Computed; + } + + declare class Component1 { + constructor(options: Options1); + get(key: K): (Data & Computed)[K]; + } + + let c1 = new Component1({ + data: { + hello: "" + } + }); + + c1.get("hello"); + + // Repro from #12625 + + interface Options2 { + data?: Data + computed?: Computed; + } + + declare class Component2 { + constructor(options: Options2); + get(key: K): (Data & Computed)[K]; + } + + // Repro from #12641 + + interface R { + p: number; + } + + function f(p: K) { + let a: any; + a[p].add; // any + } + + // Repro from #12651 + + type MethodDescriptor = { + name: string; + args: any[]; + returnValue: any; + } + + declare function dispatchMethod(name: M['name'], args: M['args']): M['returnValue']; + + type SomeMethodDescriptor = { + name: "someMethod"; + args: [string, number]; + returnValue: string[]; + } + + let result = dispatchMethod("someMethod", ["hello", 35]); + + // Repro from #13073 + + type KeyTypes = "a" | "b" + let MyThingy: { [key in KeyTypes]: string[] }; + + function addToMyThingy(key: S) { + MyThingy[key].push("a"); + } + + // Repro from #13102 + + type Handler = { + onChange: (name: keyof T) => void; + }; + + function onChangeGenericFunction(handler: Handler) { + handler.onChange('preset') + } + + // Repro from #13285 + + function updateIds, K extends string>( + obj: T, + idFields: K[], + idMapping: Partial> + ): Record { + for (const idField of idFields) { + const newId: T[K] | undefined = idMapping[obj[idField]]; + if (newId) { + obj[idField] = newId; + } + } + return obj; + } + + // Repro from #13285 + + function updateIds2( + obj: T, + key: K, + stringMap: { [oldId: string]: string } + ) { + var x = obj[key]; + stringMap[x]; // Should be OK. + } + + // Repro from #13514 + + declare function head>(list: T): T[0]; + + // Repro from #13604 + + class A { + props: T & { foo: string }; + } + + class B extends A<{ x: number}> { + f(p: this["props"]) { + p.x; + } + } + + // Repro from #13749 + + class Form { + private childFormFactories: {[K in keyof T]: (v: T[K]) => Form} + + public set(prop: K, value: T[K]) { + this.childFormFactories[prop](value) + } + } + + // Repro from #13787 + + class SampleClass

{ + public props: Readonly

; + constructor(props: P) { + this.props = Object.freeze(props); + } + } + + interface Foo { + foo: string; + } + + declare function merge(obj1: T, obj2: U): T & U; + + class AnotherSampleClass extends SampleClass { + constructor(props: T) { + const foo: Foo = { foo: "bar" }; + super(merge(props, foo)); + } + + public brokenMethod() { + this.props.foo.concat; + } + } + new AnotherSampleClass({}); + + // Positive repro from #17166 + function f3>(t: T, k: K, tk: T[K]): void { + for (let key in t) { + key = k // ok, K ==> keyof T + t[key] = tk; // ok, T[K] ==> T[keyof T] + } + } + + // # 21185 + type Predicates = { + [T in keyof TaggedRecord]: (variant: TaggedRecord[keyof TaggedRecord]) => variant is TaggedRecord[T] + } + + // Repros from #23592 + + type Example = { [K in keyof T]: T[K]["prop"] }; + type Result = Example<{ a: { prop: string }; b: { prop: number } }>; + + type Helper2 = { [K in keyof T]: Extract }; + type Example2 = { [K in keyof Helper2]: Helper2[K]["prop"] }; + type Result2 = Example2<{ 1: { prop: string }; 2: { prop: number } }>; + + // Repro from #23618 + + type DBBoolTable = { [k in K]: 0 | 1 } + enum Flag { + FLAG_1 = "flag_1", + FLAG_2 = "flag_2" + } + + type SimpleDBRecord = { staticField: number } & DBBoolTable + function getFlagsFromSimpleRecord(record: SimpleDBRecord, flags: Flag[]) { + return record[flags[0]]; + } + + type DynamicDBRecord = ({ dynamicField: number } | { dynamicField: string }) & DBBoolTable + function getFlagsFromDynamicRecord(record: DynamicDBRecord, flags: Flag[]) { + return record[flags[0]]; + } + + // Repro from #21368 + + interface I { + foo: string; + } + + declare function take(p: T): void; + + function fn(o: T, k: K) { + take<{} | null | undefined>(o[k]); + take(o[k]); + } + + // Repro from #23133 + + class Unbounded { + foo(x: T[keyof T]) { + let y: {} | undefined | null = x; + } + } + + // Repro from #23940 + + interface I7 { + x: any; + } + type Foo7 = T; + declare function f7(type: K): Foo7; + + // Repro from #21770 + + type Dict = { [key in T]: number }; + type DictDict = { [key in V]: Dict }; + + function ff1(dd: DictDict, k1: V, k2: T): number { + return dd[k1][k2]; + } + + function ff2(dd: DictDict, k1: V, k2: T): number { + const d: Dict = dd[k1]; + return d[k2]; + } + + // Repro from #26409 + + const cf1 = (t: T, k: K) => + { + const s: string = t[k]; + t.cool; + }; + + const cf2 = (t: T, k: K) => + { + const s: string = t[k]; + t.cool; + }; + \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeAsClauseRelationships.errors.txt b/tests/baselines/reference/mappedTypeAsClauseRelationships.errors.txt index 98b164a866a..eee91fc97e3 100644 --- a/tests/baselines/reference/mappedTypeAsClauseRelationships.errors.txt +++ b/tests/baselines/reference/mappedTypeAsClauseRelationships.errors.txt @@ -1,9 +1,10 @@ tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts(12,9): error TS2322: Type 'T' is not assignable to type 'Modify'. +tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts(22,9): error TS2322: Type 'T' is not assignable to type 'ModifyInclOpt'. tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts(23,9): error TS2322: Type 'T' is not assignable to type 'FilterExclOpt'. tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts(24,9): error TS2322: Type 'T' is not assignable to type 'ModifyExclOpt'. -==== tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts (3 errors) ==== +==== tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts (4 errors) ==== // From original issue #45212: type Methods = { [P in keyof T as T[P] extends Function ? P : never]: T[P] }; type H = T[keyof Methods]; // Ok @@ -28,6 +29,8 @@ tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts(24,9): e function fun2(val: T) { let x: FilterInclOpt = val; // Ok let y: ModifyInclOpt = val; // Ok + ~ +!!! error TS2322: Type 'T' is not assignable to type 'ModifyInclOpt'. let z: FilterExclOpt = val; // Error ~ !!! error TS2322: Type 'T' is not assignable to type 'FilterExclOpt'. diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess.js b/tests/baselines/reference/mappedTypeGenericIndexedAccess.js new file mode 100644 index 00000000000..a06d9b27218 --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess.js @@ -0,0 +1,105 @@ +//// [mappedTypeGenericIndexedAccess.ts] +// Repro from #49242 + +type Types = { + first: { a1: true }; + second: { a2: true }; + third: { a3: true }; +} + +class Test { + entries: { [T in keyof Types]?: Types[T][] }; + + constructor() { + this.entries = {}; + } + + addEntry(name: T, entry: Types[T]) { + if (!this.entries[name]) { + this.entries[name] = []; + } + this.entries[name]?.push(entry); + } +} + +// Repro from #49338 + +type TypesMap = { + [0]: { foo: 'bar'; }; + [1]: { a: 'b'; }; +}; + +type P = { t: T; } & TypesMap[T]; + +type TypeHandlers = { + [T in keyof TypesMap]?: (p: P) => void; +}; + +const typeHandlers: TypeHandlers = { + [0]: (p) => console.log(p.foo), + [1]: (p) => console.log(p.a), +}; + +const onSomeEvent = (p: P) => + typeHandlers[p.t]?.(p); + + +//// [mappedTypeGenericIndexedAccess.js] +"use strict"; +// Repro from #49242 +var _a; +var Test = /** @class */ (function () { + function Test() { + this.entries = {}; + } + Test.prototype.addEntry = function (name, entry) { + var _a; + if (!this.entries[name]) { + this.entries[name] = []; + } + (_a = this.entries[name]) === null || _a === void 0 ? void 0 : _a.push(entry); + }; + return Test; +}()); +var typeHandlers = (_a = {}, + _a[0] = function (p) { return console.log(p.foo); }, + _a[1] = function (p) { return console.log(p.a); }, + _a); +var onSomeEvent = function (p) { var _a; return (_a = typeHandlers[p.t]) === null || _a === void 0 ? void 0 : _a.call(typeHandlers, p); }; + + +//// [mappedTypeGenericIndexedAccess.d.ts] +declare type Types = { + first: { + a1: true; + }; + second: { + a2: true; + }; + third: { + a3: true; + }; +}; +declare class Test { + entries: { + [T in keyof Types]?: Types[T][]; + }; + constructor(); + addEntry(name: T, entry: Types[T]): void; +} +declare type TypesMap = { + [0]: { + foo: 'bar'; + }; + [1]: { + a: 'b'; + }; +}; +declare type P = { + t: T; +} & TypesMap[T]; +declare type TypeHandlers = { + [T in keyof TypesMap]?: (p: P) => void; +}; +declare const typeHandlers: TypeHandlers; +declare const onSomeEvent: (p: P) => void | undefined; diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess.symbols b/tests/baselines/reference/mappedTypeGenericIndexedAccess.symbols new file mode 100644 index 00000000000..329932a9afd --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess.symbols @@ -0,0 +1,150 @@ +=== tests/cases/compiler/mappedTypeGenericIndexedAccess.ts === +// Repro from #49242 + +type Types = { +>Types : Symbol(Types, Decl(mappedTypeGenericIndexedAccess.ts, 0, 0)) + + first: { a1: true }; +>first : Symbol(first, Decl(mappedTypeGenericIndexedAccess.ts, 2, 14)) +>a1 : Symbol(a1, Decl(mappedTypeGenericIndexedAccess.ts, 3, 12)) + + second: { a2: true }; +>second : Symbol(second, Decl(mappedTypeGenericIndexedAccess.ts, 3, 24)) +>a2 : Symbol(a2, Decl(mappedTypeGenericIndexedAccess.ts, 4, 13)) + + third: { a3: true }; +>third : Symbol(third, Decl(mappedTypeGenericIndexedAccess.ts, 4, 25)) +>a3 : Symbol(a3, Decl(mappedTypeGenericIndexedAccess.ts, 5, 12)) +} + +class Test { +>Test : Symbol(Test, Decl(mappedTypeGenericIndexedAccess.ts, 6, 1)) + + entries: { [T in keyof Types]?: Types[T][] }; +>entries : Symbol(Test.entries, Decl(mappedTypeGenericIndexedAccess.ts, 8, 12)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess.ts, 9, 16)) +>Types : Symbol(Types, Decl(mappedTypeGenericIndexedAccess.ts, 0, 0)) +>Types : Symbol(Types, Decl(mappedTypeGenericIndexedAccess.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess.ts, 9, 16)) + + constructor() { + this.entries = {}; +>this.entries : Symbol(Test.entries, Decl(mappedTypeGenericIndexedAccess.ts, 8, 12)) +>this : Symbol(Test, Decl(mappedTypeGenericIndexedAccess.ts, 6, 1)) +>entries : Symbol(Test.entries, Decl(mappedTypeGenericIndexedAccess.ts, 8, 12)) + } + + addEntry(name: T, entry: Types[T]) { +>addEntry : Symbol(Test.addEntry, Decl(mappedTypeGenericIndexedAccess.ts, 13, 5)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess.ts, 15, 13)) +>Types : Symbol(Types, Decl(mappedTypeGenericIndexedAccess.ts, 0, 0)) +>name : Symbol(name, Decl(mappedTypeGenericIndexedAccess.ts, 15, 36)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess.ts, 15, 13)) +>entry : Symbol(entry, Decl(mappedTypeGenericIndexedAccess.ts, 15, 44)) +>Types : Symbol(Types, Decl(mappedTypeGenericIndexedAccess.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess.ts, 15, 13)) + + if (!this.entries[name]) { +>this.entries : Symbol(Test.entries, Decl(mappedTypeGenericIndexedAccess.ts, 8, 12)) +>this : Symbol(Test, Decl(mappedTypeGenericIndexedAccess.ts, 6, 1)) +>entries : Symbol(Test.entries, Decl(mappedTypeGenericIndexedAccess.ts, 8, 12)) +>name : Symbol(name, Decl(mappedTypeGenericIndexedAccess.ts, 15, 36)) + + this.entries[name] = []; +>this.entries : Symbol(Test.entries, Decl(mappedTypeGenericIndexedAccess.ts, 8, 12)) +>this : Symbol(Test, Decl(mappedTypeGenericIndexedAccess.ts, 6, 1)) +>entries : Symbol(Test.entries, Decl(mappedTypeGenericIndexedAccess.ts, 8, 12)) +>name : Symbol(name, Decl(mappedTypeGenericIndexedAccess.ts, 15, 36)) + } + this.entries[name]?.push(entry); +>this.entries[name]?.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>this.entries : Symbol(Test.entries, Decl(mappedTypeGenericIndexedAccess.ts, 8, 12)) +>this : Symbol(Test, Decl(mappedTypeGenericIndexedAccess.ts, 6, 1)) +>entries : Symbol(Test.entries, Decl(mappedTypeGenericIndexedAccess.ts, 8, 12)) +>name : Symbol(name, Decl(mappedTypeGenericIndexedAccess.ts, 15, 36)) +>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>entry : Symbol(entry, Decl(mappedTypeGenericIndexedAccess.ts, 15, 44)) + } +} + +// Repro from #49338 + +type TypesMap = { +>TypesMap : Symbol(TypesMap, Decl(mappedTypeGenericIndexedAccess.ts, 21, 1)) + + [0]: { foo: 'bar'; }; +>[0] : Symbol([0], Decl(mappedTypeGenericIndexedAccess.ts, 25, 17)) +>0 : Symbol([0], Decl(mappedTypeGenericIndexedAccess.ts, 25, 17)) +>foo : Symbol(foo, Decl(mappedTypeGenericIndexedAccess.ts, 26, 10)) + + [1]: { a: 'b'; }; +>[1] : Symbol([1], Decl(mappedTypeGenericIndexedAccess.ts, 26, 25)) +>1 : Symbol([1], Decl(mappedTypeGenericIndexedAccess.ts, 26, 25)) +>a : Symbol(a, Decl(mappedTypeGenericIndexedAccess.ts, 27, 10)) + +}; + +type P = { t: T; } & TypesMap[T]; +>P : Symbol(P, Decl(mappedTypeGenericIndexedAccess.ts, 28, 2)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess.ts, 30, 7)) +>TypesMap : Symbol(TypesMap, Decl(mappedTypeGenericIndexedAccess.ts, 21, 1)) +>t : Symbol(t, Decl(mappedTypeGenericIndexedAccess.ts, 30, 36)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess.ts, 30, 7)) +>TypesMap : Symbol(TypesMap, Decl(mappedTypeGenericIndexedAccess.ts, 21, 1)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess.ts, 30, 7)) + +type TypeHandlers = { +>TypeHandlers : Symbol(TypeHandlers, Decl(mappedTypeGenericIndexedAccess.ts, 30, 59)) + + [T in keyof TypesMap]?: (p: P) => void; +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess.ts, 33, 5)) +>TypesMap : Symbol(TypesMap, Decl(mappedTypeGenericIndexedAccess.ts, 21, 1)) +>p : Symbol(p, Decl(mappedTypeGenericIndexedAccess.ts, 33, 29)) +>P : Symbol(P, Decl(mappedTypeGenericIndexedAccess.ts, 28, 2)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess.ts, 33, 5)) + +}; + +const typeHandlers: TypeHandlers = { +>typeHandlers : Symbol(typeHandlers, Decl(mappedTypeGenericIndexedAccess.ts, 36, 5)) +>TypeHandlers : Symbol(TypeHandlers, Decl(mappedTypeGenericIndexedAccess.ts, 30, 59)) + + [0]: (p) => console.log(p.foo), +>[0] : Symbol([0], Decl(mappedTypeGenericIndexedAccess.ts, 36, 36)) +>0 : Symbol([0], Decl(mappedTypeGenericIndexedAccess.ts, 36, 36)) +>p : Symbol(p, Decl(mappedTypeGenericIndexedAccess.ts, 37, 10)) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>p.foo : Symbol(foo, Decl(mappedTypeGenericIndexedAccess.ts, 26, 10)) +>p : Symbol(p, Decl(mappedTypeGenericIndexedAccess.ts, 37, 10)) +>foo : Symbol(foo, Decl(mappedTypeGenericIndexedAccess.ts, 26, 10)) + + [1]: (p) => console.log(p.a), +>[1] : Symbol([1], Decl(mappedTypeGenericIndexedAccess.ts, 37, 35)) +>1 : Symbol([1], Decl(mappedTypeGenericIndexedAccess.ts, 37, 35)) +>p : Symbol(p, Decl(mappedTypeGenericIndexedAccess.ts, 38, 10)) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>p.a : Symbol(a, Decl(mappedTypeGenericIndexedAccess.ts, 27, 10)) +>p : Symbol(p, Decl(mappedTypeGenericIndexedAccess.ts, 38, 10)) +>a : Symbol(a, Decl(mappedTypeGenericIndexedAccess.ts, 27, 10)) + +}; + +const onSomeEvent = (p: P) => +>onSomeEvent : Symbol(onSomeEvent, Decl(mappedTypeGenericIndexedAccess.ts, 41, 5)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess.ts, 41, 21)) +>TypesMap : Symbol(TypesMap, Decl(mappedTypeGenericIndexedAccess.ts, 21, 1)) +>p : Symbol(p, Decl(mappedTypeGenericIndexedAccess.ts, 41, 47)) +>P : Symbol(P, Decl(mappedTypeGenericIndexedAccess.ts, 28, 2)) +>T : Symbol(T, Decl(mappedTypeGenericIndexedAccess.ts, 41, 21)) + + typeHandlers[p.t]?.(p); +>typeHandlers : Symbol(typeHandlers, Decl(mappedTypeGenericIndexedAccess.ts, 36, 5)) +>p.t : Symbol(t, Decl(mappedTypeGenericIndexedAccess.ts, 30, 36)) +>p : Symbol(p, Decl(mappedTypeGenericIndexedAccess.ts, 41, 47)) +>t : Symbol(t, Decl(mappedTypeGenericIndexedAccess.ts, 30, 36)) +>p : Symbol(p, Decl(mappedTypeGenericIndexedAccess.ts, 41, 47)) + diff --git a/tests/baselines/reference/mappedTypeGenericIndexedAccess.types b/tests/baselines/reference/mappedTypeGenericIndexedAccess.types new file mode 100644 index 00000000000..31effd4a6ce --- /dev/null +++ b/tests/baselines/reference/mappedTypeGenericIndexedAccess.types @@ -0,0 +1,147 @@ +=== tests/cases/compiler/mappedTypeGenericIndexedAccess.ts === +// Repro from #49242 + +type Types = { +>Types : { first: { a1: true;}; second: { a2: true;}; third: { a3: true;}; } + + first: { a1: true }; +>first : { a1: true; } +>a1 : true +>true : true + + second: { a2: true }; +>second : { a2: true; } +>a2 : true +>true : true + + third: { a3: true }; +>third : { a3: true; } +>a3 : true +>true : true +} + +class Test { +>Test : Test + + entries: { [T in keyof Types]?: Types[T][] }; +>entries : { first?: { a1: true; }[] | undefined; second?: { a2: true; }[] | undefined; third?: { a3: true; }[] | undefined; } + + constructor() { + this.entries = {}; +>this.entries = {} : {} +>this.entries : { first?: { a1: true; }[] | undefined; second?: { a2: true; }[] | undefined; third?: { a3: true; }[] | undefined; } +>this : this +>entries : { first?: { a1: true; }[] | undefined; second?: { a2: true; }[] | undefined; third?: { a3: true; }[] | undefined; } +>{} : {} + } + + addEntry(name: T, entry: Types[T]) { +>addEntry : (name: T, entry: Types[T]) => void +>name : T +>entry : Types[T] + + if (!this.entries[name]) { +>!this.entries[name] : boolean +>this.entries[name] : { first?: { a1: true; }[] | undefined; second?: { a2: true; }[] | undefined; third?: { a3: true; }[] | undefined; }[T] +>this.entries : { first?: { a1: true; }[] | undefined; second?: { a2: true; }[] | undefined; third?: { a3: true; }[] | undefined; } +>this : this +>entries : { first?: { a1: true; }[] | undefined; second?: { a2: true; }[] | undefined; third?: { a3: true; }[] | undefined; } +>name : T + + this.entries[name] = []; +>this.entries[name] = [] : never[] +>this.entries[name] : { first?: { a1: true; }[] | undefined; second?: { a2: true; }[] | undefined; third?: { a3: true; }[] | undefined; }[T] +>this.entries : { first?: { a1: true; }[] | undefined; second?: { a2: true; }[] | undefined; third?: { a3: true; }[] | undefined; } +>this : this +>entries : { first?: { a1: true; }[] | undefined; second?: { a2: true; }[] | undefined; third?: { a3: true; }[] | undefined; } +>name : T +>[] : never[] + } + this.entries[name]?.push(entry); +>this.entries[name]?.push(entry) : number | undefined +>this.entries[name]?.push : ((...items: Types[T][]) => number) | undefined +>this.entries[name] : Types[T][] | undefined +>this.entries : { first?: { a1: true; }[] | undefined; second?: { a2: true; }[] | undefined; third?: { a3: true; }[] | undefined; } +>this : this +>entries : { first?: { a1: true; }[] | undefined; second?: { a2: true; }[] | undefined; third?: { a3: true; }[] | undefined; } +>name : T +>push : ((...items: Types[T][]) => number) | undefined +>entry : Types[T] + } +} + +// Repro from #49338 + +type TypesMap = { +>TypesMap : { 0: { foo: 'bar';}; 1: { a: 'b';}; } + + [0]: { foo: 'bar'; }; +>[0] : { foo: 'bar'; } +>0 : 0 +>foo : "bar" + + [1]: { a: 'b'; }; +>[1] : { a: 'b'; } +>1 : 1 +>a : "b" + +}; + +type P = { t: T; } & TypesMap[T]; +>P : P +>t : T + +type TypeHandlers = { +>TypeHandlers : { 0?: ((p: P<0>) => void) | undefined; 1?: ((p: P<1>) => void) | undefined; } + + [T in keyof TypesMap]?: (p: P) => void; +>p : P + +}; + +const typeHandlers: TypeHandlers = { +>typeHandlers : TypeHandlers +>{ [0]: (p) => console.log(p.foo), [1]: (p) => console.log(p.a),} : { 0: (p: P<0>) => void; 1: (p: P<1>) => void; } + + [0]: (p) => console.log(p.foo), +>[0] : (p: P<0>) => void +>0 : 0 +>(p) => console.log(p.foo) : (p: P<0>) => void +>p : P<0> +>console.log(p.foo) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>p.foo : "bar" +>p : P<0> +>foo : "bar" + + [1]: (p) => console.log(p.a), +>[1] : (p: P<1>) => void +>1 : 1 +>(p) => console.log(p.a) : (p: P<1>) => void +>p : P<1> +>console.log(p.a) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>p.a : "b" +>p : P<1> +>a : "b" + +}; + +const onSomeEvent = (p: P) => +>onSomeEvent : (p: P) => void | undefined +>(p: P) => typeHandlers[p.t]?.(p) : (p: P) => void | undefined +>p : P + + typeHandlers[p.t]?.(p); +>typeHandlers[p.t]?.(p) : void | undefined +>typeHandlers[p.t] : ((p: P) => void) | undefined +>typeHandlers : TypeHandlers +>p.t : T +>p : { t: T; } & ({ foo: "bar"; } | { a: "b"; }) +>t : T +>p : P + diff --git a/tests/baselines/reference/mappedTypes4.types b/tests/baselines/reference/mappedTypes4.types index 85e714a4f00..f96bf1c5e8f 100644 --- a/tests/baselines/reference/mappedTypes4.types +++ b/tests/baselines/reference/mappedTypes4.types @@ -27,17 +27,17 @@ function boxify(obj: T): Boxified { for (let k in obj) { >k : Extract ->obj : T +>obj : (T & null) | (T & object) result[k] = { value: obj[k] }; ->result[k] = { value: obj[k] } : { value: T[Extract]; } +>result[k] = { value: obj[k] } : { value: (T & object)[Extract]; } >result[k] : Boxified[Extract] >result : Boxified >k : Extract ->{ value: obj[k] } : { value: T[Extract]; } ->value : T[Extract] ->obj[k] : T[Extract] ->obj : T +>{ value: obj[k] } : { value: (T & object)[Extract]; } +>value : (T & object)[Extract] +>obj[k] : (T & object)[Extract] +>obj : T & object >k : Extract } return result; diff --git a/tests/baselines/reference/mappedTypes6.errors.txt b/tests/baselines/reference/mappedTypes6.errors.txt index 2429ea8558f..d0476d61a70 100644 --- a/tests/baselines/reference/mappedTypes6.errors.txt +++ b/tests/baselines/reference/mappedTypes6.errors.txt @@ -7,6 +7,20 @@ tests/cases/conformance/types/mapped/mappedTypes6.ts(37,5): error TS2322: Type ' Type 'T[keyof T]' is not assignable to type 'NonNullable'. Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'NonNullable'. Type 'T[string]' is not assignable to type 'NonNullable'. + Type 'T[string]' is not assignable to type 'T[P]'. + Type 'string' is not assignable to type 'P'. + 'string' is assignable to the constraint of type 'P', but 'P' could be instantiated with a different subtype of constraint 'string | number | symbol'. + Type 'T[keyof T]' is not assignable to type 'T[P]'. + Type 'keyof T' is not assignable to type 'P'. + 'keyof T' is assignable to the constraint of type 'P', but 'P' could be instantiated with a different subtype of constraint 'string | number | symbol'. + Type 'string | number | symbol' is not assignable to type 'P'. + 'string | number | symbol' is assignable to the constraint of type 'P', but 'P' could be instantiated with a different subtype of constraint 'string | number | symbol'. + Type 'string' is not assignable to type 'P'. + 'string' is assignable to the constraint of type 'P', but 'P' could be instantiated with a different subtype of constraint 'string | number | symbol'. + Type 'T[P]' is not assignable to type '{}'. + Type 'T[keyof T]' is not assignable to type '{}'. + Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{}'. + Type 'T[string]' is not assignable to type '{}'. tests/cases/conformance/types/mapped/mappedTypes6.ts(38,5): error TS2322: Type 'T' is not assignable to type 'Denullified'. tests/cases/conformance/types/mapped/mappedTypes6.ts(39,5): error TS2322: Type 'Partial' is not assignable to type 'Denullified'. tests/cases/conformance/types/mapped/mappedTypes6.ts(42,5): error TS2322: Type 'T' is not assignable to type 'Required'. @@ -77,6 +91,20 @@ tests/cases/conformance/types/mapped/mappedTypes6.ts(120,4): error TS2540: Canno !!! error TS2322: Type 'T[keyof T]' is not assignable to type 'NonNullable'. !!! error TS2322: Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'NonNullable'. !!! error TS2322: Type 'T[string]' is not assignable to type 'NonNullable'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'T[P]'. +!!! error TS2322: Type 'string' is not assignable to type 'P'. +!!! error TS2322: 'string' is assignable to the constraint of type 'P', but 'P' could be instantiated with a different subtype of constraint 'string | number | symbol'. +!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'T[P]'. +!!! error TS2322: Type 'keyof T' is not assignable to type 'P'. +!!! error TS2322: 'keyof T' is assignable to the constraint of type 'P', but 'P' could be instantiated with a different subtype of constraint 'string | number | symbol'. +!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'P'. +!!! error TS2322: 'string | number | symbol' is assignable to the constraint of type 'P', but 'P' could be instantiated with a different subtype of constraint 'string | number | symbol'. +!!! error TS2322: Type 'string' is not assignable to type 'P'. +!!! error TS2322: 'string' is assignable to the constraint of type 'P', but 'P' could be instantiated with a different subtype of constraint 'string | number | symbol'. +!!! error TS2322: Type 'T[P]' is not assignable to type '{}'. +!!! error TS2322: Type 'T[keyof T]' is not assignable to type '{}'. +!!! error TS2322: Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{}'. +!!! error TS2322: Type 'T[string]' is not assignable to type '{}'. w = y; // Error ~ !!! error TS2322: Type 'T' is not assignable to type 'Denullified'. diff --git a/tests/baselines/reference/mappedTypesAndObjects.errors.txt b/tests/baselines/reference/mappedTypesAndObjects.errors.txt new file mode 100644 index 00000000000..c32fc58b370 --- /dev/null +++ b/tests/baselines/reference/mappedTypesAndObjects.errors.txt @@ -0,0 +1,54 @@ +tests/cases/conformance/types/mapped/mappedTypesAndObjects.ts(25,11): error TS2430: Interface 'E1' incorrectly extends interface 'Base'. + Types of property 'foo' are incompatible. + Type 'T' is not assignable to type '{ [key: string]: any; }'. + + +==== tests/cases/conformance/types/mapped/mappedTypesAndObjects.ts (1 errors) ==== + function f1(x: Partial, y: Readonly) { + let obj: {}; + obj = x; + obj = y; + } + + function f2(x: Partial, y: Readonly) { + let obj: { [x: string]: any }; + obj = x; + obj = y; + } + + function f3(x: Partial) { + x = {}; + } + + // Repro from #12900 + + interface Base { + foo: { [key: string]: any }; + bar: any; + baz: any; + } + + interface E1 extends Base { + ~~ +!!! error TS2430: Interface 'E1' incorrectly extends interface 'Base'. +!!! error TS2430: Types of property 'foo' are incompatible. +!!! error TS2430: Type 'T' is not assignable to type '{ [key: string]: any; }'. +!!! related TS2208 tests/cases/conformance/types/mapped/mappedTypesAndObjects.ts:25:14: This type parameter probably needs an `extends object` constraint. + foo: T; + } + + interface Something { name: string, value: string }; + interface E2 extends Base { + foo: Partial; // or other mapped type + } + + interface E3 extends Base { + foo: Partial; // or other mapped type + } + + // Repro from #13747 + + class Form { + private values: {[P in keyof T]?: T[P]} = {} + } + \ No newline at end of file diff --git a/tests/baselines/reference/narrowByEquality.types b/tests/baselines/reference/narrowByEquality.types index 4f5c8a51958..f34a49558b2 100644 --- a/tests/baselines/reference/narrowByEquality.types +++ b/tests/baselines/reference/narrowByEquality.types @@ -144,7 +144,7 @@ if (xUnknown == null) { } else { xUnknown ->xUnknown : unknown +>xUnknown : {} } if (xUnknown != null) { @@ -153,7 +153,7 @@ if (xUnknown != null) { >null : null xUnknown; ->xUnknown : unknown +>xUnknown : {} } else { xUnknown; diff --git a/tests/baselines/reference/narrowingByTypeofInSwitch.types b/tests/baselines/reference/narrowingByTypeofInSwitch.types index 96897cd71de..8d06e9243c6 100644 --- a/tests/baselines/reference/narrowingByTypeofInSwitch.types +++ b/tests/baselines/reference/narrowingByTypeofInSwitch.types @@ -552,14 +552,14 @@ function multipleGenericFuse(xy: X | case 'function': return [xy, 1]; >'function' : "function" ->[xy, 1] : [X, 1] ->xy : X +>[xy, 1] : [X & Function, 1] +>xy : X & Function >1 : 1 case 'object': return [xy, 'two']; >'object' : "object" ->[xy, 'two'] : [Y, string] ->xy : Y +>[xy, 'two'] : [Y & object, string] +>xy : Y & object >'two' : "two" case 'number': return [xy] @@ -843,7 +843,7 @@ function narrowingNarrows(x: {} | undefined) { case 'object': const _: {} = x; return; >'object' : "object" >_ : {} ->x : {} +>x : object case 'string': assertString(x); return; >'string' : "string" @@ -1092,14 +1092,14 @@ function multipleGenericFuseWithBoth case `function`: return [xy, 1]; >`function` : "function" ->[xy, 1] : [X, 1] ->xy : X +>[xy, 1] : [X & Function, 1] +>xy : X & Function >1 : 1 case 'object': return [xy, 'two']; >'object' : "object" ->[xy, 'two'] : [Y, string] ->xy : Y +>[xy, 'two'] : [Y & object, string] +>xy : Y & object >'two' : "two" case `number`: return [xy] diff --git a/tests/baselines/reference/narrowingTruthyObject.types b/tests/baselines/reference/narrowingTruthyObject.types index c562f3da2d3..463faf95556 100644 --- a/tests/baselines/reference/narrowingTruthyObject.types +++ b/tests/baselines/reference/narrowingTruthyObject.types @@ -35,7 +35,7 @@ function foo(x: unknown, b: boolean) { >x : unknown >typeof x === 'object' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} >'object' : "object" x.toString(); @@ -51,7 +51,7 @@ function foo(x: unknown, b: boolean) { >x : unknown >typeof x === 'object' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} >'object' : "object" x.toString(); @@ -67,7 +67,7 @@ function foo(x: unknown, b: boolean) { >b : boolean >typeof x === 'object' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} >'object' : "object" x.toString(); @@ -85,7 +85,7 @@ function foo(x: unknown, b: boolean) { >b : true >typeof x === 'object' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} >'object' : "object" x.toString(); @@ -107,7 +107,7 @@ function foo(x: unknown, b: boolean) { >b : true >typeof x === 'object' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} >'object' : "object" x.toString(); @@ -130,7 +130,7 @@ function f1(x: unknown): any { >x : unknown >typeof x === 'object' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} >'object' : "object" >x.hasOwnProperty('x') : boolean >x.hasOwnProperty : (v: PropertyKey) => boolean diff --git a/tests/baselines/reference/narrowingTypeofFunction.types b/tests/baselines/reference/narrowingTypeofFunction.types index 6290fe95c37..19b11f2b2fe 100644 --- a/tests/baselines/reference/narrowingTypeofFunction.types +++ b/tests/baselines/reference/narrowingTypeofFunction.types @@ -35,7 +35,7 @@ function f2(x: (T & F) | T & string) { >"function" : "function" x; ->x : (T & F) | (T & string) +>x : T & F } else { x; diff --git a/tests/baselines/reference/neverType.js b/tests/baselines/reference/neverType.js index eb7ee331480..9d81d49d76a 100644 --- a/tests/baselines/reference/neverType.js +++ b/tests/baselines/reference/neverType.js @@ -180,7 +180,7 @@ declare function infiniteLoop1(): void; declare function infiniteLoop2(): never; declare function move1(direction: "up" | "down"): 1 | -1; declare function move2(direction: "up" | "down"): 1 | -1; -declare function check(x: T | undefined): T; +declare function check(x: T | undefined): NonNullable; declare class C { void1(): void; void2(): void; diff --git a/tests/baselines/reference/neverType.types b/tests/baselines/reference/neverType.types index 7ae38d11f76..b7e08eb503a 100644 --- a/tests/baselines/reference/neverType.types +++ b/tests/baselines/reference/neverType.types @@ -112,11 +112,11 @@ function move2(direction: "up" | "down") { } function check(x: T | undefined) { ->check : (x: T | undefined) => T +>check : (x: T | undefined) => NonNullable >x : T | undefined return x || error("Undefined value"); ->x || error("Undefined value") : T +>x || error("Undefined value") : NonNullable >x : T | undefined >error("Undefined value") : never >error : (message: string) => never diff --git a/tests/baselines/reference/nodeNextImportModeImplicitIndexResolution2.errors.txt b/tests/baselines/reference/nodeNextImportModeImplicitIndexResolution2.errors.txt new file mode 100644 index 00000000000..914722e2f4d --- /dev/null +++ b/tests/baselines/reference/nodeNextImportModeImplicitIndexResolution2.errors.txt @@ -0,0 +1,44 @@ +/index.cts(4,21): error TS2307: Cannot find module 'dedent4' or its corresponding type declarations. +/index.mts(4,21): error TS2307: Cannot find module 'dedent4' or its corresponding type declarations. + + +==== /node_modules/@types/dedent/package.json (0 errors) ==== + { "name": "@types/dedent", "version": "1.0.0", "main": "" } + +==== /node_modules/@types/dedent2/package.json (0 errors) ==== + { "name": "@types/dedent2", "version": "1.0.0", "main": "asdfasdfasdf" } + +==== /node_modules/@types/dedent3/package.json (0 errors) ==== + { "name": "@types/dedent3", "version": "1.0.0", "main": "asdfasdfasdf", "exports": null } + +==== /node_modules/@types/dedent4/package.json (0 errors) ==== + { "name": "@types/dedent4", "version": "1.0.0", "main": "asdfasdfasdf", "exports": "./asdfasdfasdf" } + +==== /node_modules/@types/dedent/index.d.ts (0 errors) ==== + export {}; + +==== /node_modules/@types/dedent2/index.d.ts (0 errors) ==== + export {}; + +==== /node_modules/@types/dedent3/index.d.ts (0 errors) ==== + export {}; + +==== /node_modules/@types/dedent4/index.d.ts (0 errors) ==== + export {}; + +==== /index.mts (1 errors) ==== + import dedent from "dedent"; + import dedent2 from "dedent2"; + import dedent3 from "dedent3"; + import dedent4 from "dedent4"; // Error + ~~~~~~~~~ +!!! error TS2307: Cannot find module 'dedent4' or its corresponding type declarations. + +==== /index.cts (1 errors) ==== + import dedent from "dedent"; + import dedent2 from "dedent2"; + import dedent3 from "dedent3"; + import dedent4 from "dedent4"; // Error + ~~~~~~~~~ +!!! error TS2307: Cannot find module 'dedent4' or its corresponding type declarations. + \ No newline at end of file diff --git a/tests/baselines/reference/nodeNextImportModeImplicitIndexResolution2.js b/tests/baselines/reference/nodeNextImportModeImplicitIndexResolution2.js new file mode 100644 index 00000000000..3125a73f6e7 --- /dev/null +++ b/tests/baselines/reference/nodeNextImportModeImplicitIndexResolution2.js @@ -0,0 +1,44 @@ +//// [tests/cases/compiler/nodeNextImportModeImplicitIndexResolution2.ts] //// + +//// [package.json] +{ "name": "@types/dedent", "version": "1.0.0", "main": "" } + +//// [package.json] +{ "name": "@types/dedent2", "version": "1.0.0", "main": "asdfasdfasdf" } + +//// [package.json] +{ "name": "@types/dedent3", "version": "1.0.0", "main": "asdfasdfasdf", "exports": null } + +//// [package.json] +{ "name": "@types/dedent4", "version": "1.0.0", "main": "asdfasdfasdf", "exports": "./asdfasdfasdf" } + +//// [index.d.ts] +export {}; + +//// [index.d.ts] +export {}; + +//// [index.d.ts] +export {}; + +//// [index.d.ts] +export {}; + +//// [index.mts] +import dedent from "dedent"; +import dedent2 from "dedent2"; +import dedent3 from "dedent3"; +import dedent4 from "dedent4"; // Error + +//// [index.cts] +import dedent from "dedent"; +import dedent2 from "dedent2"; +import dedent3 from "dedent3"; +import dedent4 from "dedent4"; // Error + + +//// [index.mjs] +export {}; +//// [index.cjs] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/tests/baselines/reference/nodeNextImportModeImplicitIndexResolution2.symbols b/tests/baselines/reference/nodeNextImportModeImplicitIndexResolution2.symbols new file mode 100644 index 00000000000..5685121775b --- /dev/null +++ b/tests/baselines/reference/nodeNextImportModeImplicitIndexResolution2.symbols @@ -0,0 +1,38 @@ +=== /node_modules/@types/dedent/index.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /node_modules/@types/dedent2/index.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /node_modules/@types/dedent3/index.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /node_modules/@types/dedent4/index.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /index.mts === +import dedent from "dedent"; +>dedent : Symbol(dedent, Decl(index.mts, 0, 6)) + +import dedent2 from "dedent2"; +>dedent2 : Symbol(dedent2, Decl(index.mts, 1, 6)) + +import dedent3 from "dedent3"; +>dedent3 : Symbol(dedent3, Decl(index.mts, 2, 6)) + +import dedent4 from "dedent4"; // Error +>dedent4 : Symbol(dedent4, Decl(index.mts, 3, 6)) + +=== /index.cts === +import dedent from "dedent"; +>dedent : Symbol(dedent, Decl(index.cts, 0, 6)) + +import dedent2 from "dedent2"; +>dedent2 : Symbol(dedent2, Decl(index.cts, 1, 6)) + +import dedent3 from "dedent3"; +>dedent3 : Symbol(dedent3, Decl(index.cts, 2, 6)) + +import dedent4 from "dedent4"; // Error +>dedent4 : Symbol(dedent4, Decl(index.cts, 3, 6)) + diff --git a/tests/baselines/reference/nodeNextImportModeImplicitIndexResolution2.types b/tests/baselines/reference/nodeNextImportModeImplicitIndexResolution2.types new file mode 100644 index 00000000000..a2a37da0ecd --- /dev/null +++ b/tests/baselines/reference/nodeNextImportModeImplicitIndexResolution2.types @@ -0,0 +1,38 @@ +=== /node_modules/@types/dedent/index.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /node_modules/@types/dedent2/index.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /node_modules/@types/dedent3/index.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /node_modules/@types/dedent4/index.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /index.mts === +import dedent from "dedent"; +>dedent : typeof dedent + +import dedent2 from "dedent2"; +>dedent2 : typeof dedent2 + +import dedent3 from "dedent3"; +>dedent3 : typeof dedent3 + +import dedent4 from "dedent4"; // Error +>dedent4 : any + +=== /index.cts === +import dedent from "dedent"; +>dedent : typeof dedent + +import dedent2 from "dedent2"; +>dedent2 : typeof dedent2 + +import dedent3 from "dedent3"; +>dedent3 : typeof dedent3 + +import dedent4 from "dedent4"; // Error +>dedent4 : any + diff --git a/tests/baselines/reference/nonNullParameterExtendingStringAssignableToString.types b/tests/baselines/reference/nonNullParameterExtendingStringAssignableToString.types index 5f9783c5f90..64c099cfa4e 100644 --- a/tests/baselines/reference/nonNullParameterExtendingStringAssignableToString.types +++ b/tests/baselines/reference/nonNullParameterExtendingStringAssignableToString.types @@ -25,7 +25,7 @@ function fn(one: T, two: U) { foo(two!); >foo(two!) : void >foo : (p: string) => void ->two! : NonNullable +>two! : U >two : U foo(three!); // this line is the important one diff --git a/tests/baselines/reference/nonNullableTypes1.js b/tests/baselines/reference/nonNullableTypes1.js new file mode 100644 index 00000000000..51d4918aa60 --- /dev/null +++ b/tests/baselines/reference/nonNullableTypes1.js @@ -0,0 +1,85 @@ +//// [nonNullableTypes1.ts] +function f1(x: T) { + let y = x || "hello"; // NonNullable | string +} + +function error(): never { + throw new Error(); +} + +function f2(x: T) { // NonNullable + return x || error(); +} + +function f3(x: unknown) { + let y = x!; // {} +} + +function f4(obj: T) { + if (obj?.x === "hello") { + obj; // NonNullable + } + if (obj?.x) { + obj; // NonNullable + } + if (typeof obj?.x === "string") { + obj; // NonNullable + } +} + +class A { + x = "hello"; + foo() { + let zz = this?.x; // string + } +} + + +//// [nonNullableTypes1.js] +"use strict"; +function f1(x) { + var y = x || "hello"; // NonNullable | string +} +function error() { + throw new Error(); +} +function f2(x) { + return x || error(); +} +function f3(x) { + var y = x; // {} +} +function f4(obj) { + if ((obj === null || obj === void 0 ? void 0 : obj.x) === "hello") { + obj; // NonNullable + } + if (obj === null || obj === void 0 ? void 0 : obj.x) { + obj; // NonNullable + } + if (typeof (obj === null || obj === void 0 ? void 0 : obj.x) === "string") { + obj; // NonNullable + } +} +var A = /** @class */ (function () { + function A() { + this.x = "hello"; + } + A.prototype.foo = function () { + var zz = this === null || this === void 0 ? void 0 : this.x; // string + }; + return A; +}()); + + +//// [nonNullableTypes1.d.ts] +declare function f1(x: T): void; +declare function error(): never; +declare function f2(x: T): NonNullable; +declare function f3(x: unknown): void; +declare function f4(obj: T): void; +declare class A { + x: string; + foo(): void; +} diff --git a/tests/baselines/reference/nonNullableTypes1.symbols b/tests/baselines/reference/nonNullableTypes1.symbols new file mode 100644 index 00000000000..7737d22f680 --- /dev/null +++ b/tests/baselines/reference/nonNullableTypes1.symbols @@ -0,0 +1,89 @@ +=== tests/cases/compiler/nonNullableTypes1.ts === +function f1(x: T) { +>f1 : Symbol(f1, Decl(nonNullableTypes1.ts, 0, 0)) +>T : Symbol(T, Decl(nonNullableTypes1.ts, 0, 12)) +>x : Symbol(x, Decl(nonNullableTypes1.ts, 0, 15)) +>T : Symbol(T, Decl(nonNullableTypes1.ts, 0, 12)) + + let y = x || "hello"; // NonNullable | string +>y : Symbol(y, Decl(nonNullableTypes1.ts, 1, 7)) +>x : Symbol(x, Decl(nonNullableTypes1.ts, 0, 15)) +} + +function error(): never { +>error : Symbol(error, Decl(nonNullableTypes1.ts, 2, 1)) + + throw new Error(); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +} + +function f2(x: T) { // NonNullable +>f2 : Symbol(f2, Decl(nonNullableTypes1.ts, 6, 1)) +>T : Symbol(T, Decl(nonNullableTypes1.ts, 8, 12)) +>x : Symbol(x, Decl(nonNullableTypes1.ts, 8, 15)) +>T : Symbol(T, Decl(nonNullableTypes1.ts, 8, 12)) + + return x || error(); +>x : Symbol(x, Decl(nonNullableTypes1.ts, 8, 15)) +>error : Symbol(error, Decl(nonNullableTypes1.ts, 2, 1)) +} + +function f3(x: unknown) { +>f3 : Symbol(f3, Decl(nonNullableTypes1.ts, 10, 1)) +>x : Symbol(x, Decl(nonNullableTypes1.ts, 12, 12)) + + let y = x!; // {} +>y : Symbol(y, Decl(nonNullableTypes1.ts, 13, 7)) +>x : Symbol(x, Decl(nonNullableTypes1.ts, 12, 12)) +} + +function f4(obj: T) { +>f4 : Symbol(f4, Decl(nonNullableTypes1.ts, 14, 1)) +>T : Symbol(T, Decl(nonNullableTypes1.ts, 16, 12)) +>x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) +>obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) +>T : Symbol(T, Decl(nonNullableTypes1.ts, 16, 12)) + + if (obj?.x === "hello") { +>obj?.x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) +>obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) +>x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) + + obj; // NonNullable +>obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) + } + if (obj?.x) { +>obj?.x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) +>obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) +>x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) + + obj; // NonNullable +>obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) + } + if (typeof obj?.x === "string") { +>obj?.x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) +>obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) +>x : Symbol(x, Decl(nonNullableTypes1.ts, 16, 23)) + + obj; // NonNullable +>obj : Symbol(obj, Decl(nonNullableTypes1.ts, 16, 49)) + } +} + +class A { +>A : Symbol(A, Decl(nonNullableTypes1.ts, 26, 1)) + + x = "hello"; +>x : Symbol(A.x, Decl(nonNullableTypes1.ts, 28, 9)) + + foo() { +>foo : Symbol(A.foo, Decl(nonNullableTypes1.ts, 29, 16)) + + let zz = this?.x; // string +>zz : Symbol(zz, Decl(nonNullableTypes1.ts, 31, 11)) +>this?.x : Symbol(A.x, Decl(nonNullableTypes1.ts, 28, 9)) +>this : Symbol(A, Decl(nonNullableTypes1.ts, 26, 1)) +>x : Symbol(A.x, Decl(nonNullableTypes1.ts, 28, 9)) + } +} + diff --git a/tests/baselines/reference/nonNullableTypes1.types b/tests/baselines/reference/nonNullableTypes1.types new file mode 100644 index 00000000000..3d319114e79 --- /dev/null +++ b/tests/baselines/reference/nonNullableTypes1.types @@ -0,0 +1,95 @@ +=== tests/cases/compiler/nonNullableTypes1.ts === +function f1(x: T) { +>f1 : (x: T) => void +>x : T + + let y = x || "hello"; // NonNullable | string +>y : string | NonNullable +>x || "hello" : "hello" | NonNullable +>x : T +>"hello" : "hello" +} + +function error(): never { +>error : () => never + + throw new Error(); +>new Error() : Error +>Error : ErrorConstructor +} + +function f2(x: T) { // NonNullable +>f2 : (x: T) => NonNullable +>x : T + + return x || error(); +>x || error() : NonNullable +>x : T +>error() : never +>error : () => never +} + +function f3(x: unknown) { +>f3 : (x: unknown) => void +>x : unknown + + let y = x!; // {} +>y : {} +>x! : {} +>x : unknown +} + +function f4(obj: T) { +>f4 : (obj: T) => void +>x : string +>obj : T + + if (obj?.x === "hello") { +>obj?.x === "hello" : boolean +>obj?.x : string | undefined +>obj : { x: string; } | undefined +>x : string | undefined +>"hello" : "hello" + + obj; // NonNullable +>obj : NonNullable + } + if (obj?.x) { +>obj?.x : string | undefined +>obj : { x: string; } | undefined +>x : string | undefined + + obj; // NonNullable +>obj : NonNullable + } + if (typeof obj?.x === "string") { +>typeof obj?.x === "string" : boolean +>typeof obj?.x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>obj?.x : string | undefined +>obj : { x: string; } | undefined +>x : string | undefined +>"string" : "string" + + obj; // NonNullable +>obj : NonNullable + } +} + +class A { +>A : A + + x = "hello"; +>x : string +>"hello" : "hello" + + foo() { +>foo : () => void + + let zz = this?.x; // string +>zz : string +>this?.x : string +>this : this +>x : string + } +} + diff --git a/tests/baselines/reference/nonPrimitiveUnionIntersection.errors.txt b/tests/baselines/reference/nonPrimitiveUnionIntersection.errors.txt index d4c970c5064..84c3f768436 100644 --- a/tests/baselines/reference/nonPrimitiveUnionIntersection.errors.txt +++ b/tests/baselines/reference/nonPrimitiveUnionIntersection.errors.txt @@ -1,6 +1,5 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(1,5): error TS2322: Type 'string' is not assignable to type 'never'. -tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(3,5): error TS2322: Type 'number' is not assignable to type 'object & {}'. - Type 'number' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(3,5): error TS2322: Type 'number' is not assignable to type 'object'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(4,1): error TS2322: Type 'string' is not assignable to type 'never'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(8,38): error TS2322: Type '{ bar: string; }' is not assignable to type 'object & { err: string; }'. Object literal may only specify known properties, and 'bar' does not exist in type 'object & { err: string; }'. @@ -13,8 +12,7 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(8,38 var b: object | string = ""; // ok var c: object & {} = 123; // error ~ -!!! error TS2322: Type 'number' is not assignable to type 'object & {}'. -!!! error TS2322: Type 'number' is not assignable to type 'object'. +!!! error TS2322: Type 'number' is not assignable to type 'object'. a = b; // error ~ !!! error TS2322: Type 'string' is not assignable to type 'never'. diff --git a/tests/baselines/reference/nonPrimitiveUnionIntersection.types b/tests/baselines/reference/nonPrimitiveUnionIntersection.types index ef7e2f8928b..0a4a870a15b 100644 --- a/tests/baselines/reference/nonPrimitiveUnionIntersection.types +++ b/tests/baselines/reference/nonPrimitiveUnionIntersection.types @@ -8,7 +8,7 @@ var b: object | string = ""; // ok >"" : "" var c: object & {} = 123; // error ->c : object & {} +>c : object >123 : 123 a = b; // error @@ -22,7 +22,7 @@ b = a; // ok >a : never const foo: object & {} = {bar: 'bar'}; // ok ->foo : object & {} +>foo : object >{bar: 'bar'} : { bar: string; } >bar : string >'bar' : "bar" diff --git a/tests/baselines/reference/nullishCoalescingOperator2.types b/tests/baselines/reference/nullishCoalescingOperator2.types index dd1e31c4038..085b3de8d59 100644 --- a/tests/baselines/reference/nullishCoalescingOperator2.types +++ b/tests/baselines/reference/nullishCoalescingOperator2.types @@ -75,8 +75,8 @@ const aa6 = a6 ?? 'whatever' >'whatever' : "whatever" const aa7 = a7 ?? 'whatever' ->aa7 : unknown ->a7 ?? 'whatever' : unknown +>aa7 : {} +>a7 ?? 'whatever' : {} >a7 : unknown >'whatever' : "whatever" diff --git a/tests/baselines/reference/nullishCoalescingOperator_es2020.types b/tests/baselines/reference/nullishCoalescingOperator_es2020.types index 2dead6366b7..aec3adb3d46 100644 --- a/tests/baselines/reference/nullishCoalescingOperator_es2020.types +++ b/tests/baselines/reference/nullishCoalescingOperator_es2020.types @@ -75,8 +75,8 @@ const aa6 = a6 ?? 'whatever' >'whatever' : "whatever" const aa7 = a7 ?? 'whatever' ->aa7 : unknown ->a7 ?? 'whatever' : unknown +>aa7 : {} +>a7 ?? 'whatever' : {} >a7 : unknown >'whatever' : "whatever" diff --git a/tests/baselines/reference/omittedExpressionForOfLoop.errors.txt b/tests/baselines/reference/omittedExpressionForOfLoop.errors.txt new file mode 100644 index 00000000000..145af55d190 --- /dev/null +++ b/tests/baselines/reference/omittedExpressionForOfLoop.errors.txt @@ -0,0 +1,26 @@ +tests/cases/compiler/omittedExpressionForOfLoop.ts(1,19): error TS2304: Cannot find name 'doesNotExist'. +tests/cases/compiler/omittedExpressionForOfLoop.ts(4,19): error TS2532: Object is possibly 'undefined'. +tests/cases/compiler/omittedExpressionForOfLoop.ts(7,12): error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator. +tests/cases/compiler/omittedExpressionForOfLoop.ts(10,12): error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator. + + +==== tests/cases/compiler/omittedExpressionForOfLoop.ts (4 errors) ==== + for (const [,] of doesNotExist) { + ~~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'doesNotExist'. + } + + for (const [,] of undefined) { + ~~~~~~~~~ +!!! error TS2532: Object is possibly 'undefined'. + } + + for (const [,] of []) { + ~~~ +!!! error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator. + } + + for (const [] of []) { + ~~ +!!! error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator. + } \ No newline at end of file diff --git a/tests/baselines/reference/omittedExpressionForOfLoop.js b/tests/baselines/reference/omittedExpressionForOfLoop.js new file mode 100644 index 00000000000..6a96b3b73ed --- /dev/null +++ b/tests/baselines/reference/omittedExpressionForOfLoop.js @@ -0,0 +1,23 @@ +//// [omittedExpressionForOfLoop.ts] +for (const [,] of doesNotExist) { +} + +for (const [,] of undefined) { +} + +for (const [,] of []) { +} + +for (const [] of []) { +} + +//// [omittedExpressionForOfLoop.js] +"use strict"; +for (const [,] of doesNotExist) { +} +for (const [,] of undefined) { +} +for (const [,] of []) { +} +for (const [] of []) { +} diff --git a/tests/baselines/reference/omittedExpressionForOfLoop.symbols b/tests/baselines/reference/omittedExpressionForOfLoop.symbols new file mode 100644 index 00000000000..9ea7c1c04cf --- /dev/null +++ b/tests/baselines/reference/omittedExpressionForOfLoop.symbols @@ -0,0 +1,13 @@ +=== tests/cases/compiler/omittedExpressionForOfLoop.ts === +for (const [,] of doesNotExist) { +} + +for (const [,] of undefined) { +>undefined : Symbol(undefined) +} + +for (const [,] of []) { +} + +for (const [] of []) { +} diff --git a/tests/baselines/reference/omittedExpressionForOfLoop.types b/tests/baselines/reference/omittedExpressionForOfLoop.types new file mode 100644 index 00000000000..76ac26753b4 --- /dev/null +++ b/tests/baselines/reference/omittedExpressionForOfLoop.types @@ -0,0 +1,19 @@ +=== tests/cases/compiler/omittedExpressionForOfLoop.ts === +for (const [,] of doesNotExist) { +> : undefined +>doesNotExist : any +} + +for (const [,] of undefined) { +> : undefined +>undefined : undefined +} + +for (const [,] of []) { +> : undefined +>[] : never[] +} + +for (const [] of []) { +>[] : never[] +} diff --git a/tests/baselines/reference/privateIdentifierChain.1.types b/tests/baselines/reference/privateIdentifierChain.1.types index faf9a763c04..34deba67625 100644 --- a/tests/baselines/reference/privateIdentifierChain.1.types +++ b/tests/baselines/reference/privateIdentifierChain.1.types @@ -28,10 +28,10 @@ class A { this?.getA().#b; // Error >this?.getA().#b : A | undefined ->this?.getA() : A | undefined ->this?.getA : (() => A) | undefined +>this?.getA() : A +>this?.getA : () => A >this : this ->getA : (() => A) | undefined +>getA : () => A } } diff --git a/tests/baselines/reference/propTypeValidatorInference.types b/tests/baselines/reference/propTypeValidatorInference.types index ed705dbd730..2a2feafc303 100644 --- a/tests/baselines/reference/propTypeValidatorInference.types +++ b/tests/baselines/reference/propTypeValidatorInference.types @@ -179,7 +179,7 @@ const arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({ // TS checking const propTypes: PropTypesMap = { >propTypes : PropTypes.ValidationMap ->{ any: PropTypes.any, array: PropTypes.array.isRequired, bool: PropTypes.bool.isRequired, shape: PropTypes.shape(innerProps).isRequired, oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired,} : { any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>; } +>{ any: PropTypes.any, array: PropTypes.array.isRequired, bool: PropTypes.bool.isRequired, shape: PropTypes.shape(innerProps).isRequired, oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired,} : { any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>>>; } any: PropTypes.any, >any : PropTypes.Requireable @@ -204,31 +204,31 @@ const propTypes: PropTypesMap = { >isRequired : PropTypes.Validator shape: PropTypes.shape(innerProps).isRequired, ->shape : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> ->PropTypes.shape(innerProps).isRequired : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> +>shape : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>> +>PropTypes.shape(innerProps).isRequired : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>> >PropTypes.shape(innerProps) : PropTypes.Requireable; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> >PropTypes.shape :

>(type: P) => PropTypes.Requireable> >PropTypes : typeof PropTypes >shape :

>(type: P) => PropTypes.Requireable> >innerProps : { foo: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; } ->isRequired : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> +>isRequired : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>> oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, ->oneOfType : PropTypes.Validator; bar: PropTypes.Validator; }>> ->PropTypes.oneOfType(arrayOfTypes).isRequired : PropTypes.Validator; bar: PropTypes.Validator; }>> ->PropTypes.oneOfType(arrayOfTypes) : PropTypes.Requireable; bar: PropTypes.Validator; }>> +>oneOfType : PropTypes.Validator; bar: PropTypes.Validator; }>>>> +>PropTypes.oneOfType(arrayOfTypes).isRequired : PropTypes.Validator; bar: PropTypes.Validator; }>>>> +>PropTypes.oneOfType(arrayOfTypes) : PropTypes.Requireable; bar: PropTypes.Validator; }>>> >PropTypes.oneOfType : >(types: T[]) => PropTypes.Requireable>> >PropTypes : typeof PropTypes >oneOfType : >(types: T[]) => PropTypes.Requireable>> >arrayOfTypes : (PropTypes.Requireable | PropTypes.Requireable | PropTypes.Requireable; bar: PropTypes.Validator; }>>)[] ->isRequired : PropTypes.Validator; bar: PropTypes.Validator; }>> +>isRequired : PropTypes.Validator; bar: PropTypes.Validator; }>>>> }; // JS checking const propTypesWithoutAnnotation = { ->propTypesWithoutAnnotation : { any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>; } ->{ any: PropTypes.any, array: PropTypes.array.isRequired, bool: PropTypes.bool.isRequired, shape: PropTypes.shape(innerProps).isRequired, oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired,} : { any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>; } +>propTypesWithoutAnnotation : { any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>>>; } +>{ any: PropTypes.any, array: PropTypes.array.isRequired, bool: PropTypes.bool.isRequired, shape: PropTypes.shape(innerProps).isRequired, oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired,} : { any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>>>; } any: PropTypes.any, >any : PropTypes.Requireable @@ -253,24 +253,24 @@ const propTypesWithoutAnnotation = { >isRequired : PropTypes.Validator shape: PropTypes.shape(innerProps).isRequired, ->shape : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> ->PropTypes.shape(innerProps).isRequired : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> +>shape : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>> +>PropTypes.shape(innerProps).isRequired : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>> >PropTypes.shape(innerProps) : PropTypes.Requireable; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> >PropTypes.shape :

>(type: P) => PropTypes.Requireable> >PropTypes : typeof PropTypes >shape :

>(type: P) => PropTypes.Requireable> >innerProps : { foo: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; } ->isRequired : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>> +>isRequired : PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>> oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, ->oneOfType : PropTypes.Validator; bar: PropTypes.Validator; }>> ->PropTypes.oneOfType(arrayOfTypes).isRequired : PropTypes.Validator; bar: PropTypes.Validator; }>> ->PropTypes.oneOfType(arrayOfTypes) : PropTypes.Requireable; bar: PropTypes.Validator; }>> +>oneOfType : PropTypes.Validator; bar: PropTypes.Validator; }>>>> +>PropTypes.oneOfType(arrayOfTypes).isRequired : PropTypes.Validator; bar: PropTypes.Validator; }>>>> +>PropTypes.oneOfType(arrayOfTypes) : PropTypes.Requireable; bar: PropTypes.Validator; }>>> >PropTypes.oneOfType : >(types: T[]) => PropTypes.Requireable>> >PropTypes : typeof PropTypes >oneOfType : >(types: T[]) => PropTypes.Requireable>> >arrayOfTypes : (PropTypes.Requireable | PropTypes.Requireable | PropTypes.Requireable; bar: PropTypes.Validator; }>>)[] ->isRequired : PropTypes.Validator; bar: PropTypes.Validator; }>> +>isRequired : PropTypes.Validator; bar: PropTypes.Validator; }>>>> }; @@ -280,9 +280,9 @@ type ExtractedProps = PropTypes.InferProps; >propTypes : PropTypes.ValidationMap type ExtractedPropsWithoutAnnotation = PropTypes.InferProps; ->ExtractedPropsWithoutAnnotation : PropTypes.InferPropsInner; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>; }, PropTypes.RequiredKeys<{ any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>; }>>> & Partial; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>; }, "any">>> +>ExtractedPropsWithoutAnnotation : PropTypes.InferPropsInner; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>>>; }, PropTypes.RequiredKeys<{ any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>>>; }>>> & Partial; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>>>; }, "any">>> >PropTypes : any ->propTypesWithoutAnnotation : { any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>; } +>propTypesWithoutAnnotation : { any: PropTypes.Requireable; array: PropTypes.Validator; bool: PropTypes.Validator; shape: PropTypes.Validator; bar: PropTypes.Requireable; baz: PropTypes.Requireable; }>>>; oneOfType: PropTypes.Validator; bar: PropTypes.Validator; }>>>>; } type ExtractPropsMatch = ExtractedProps extends ExtractedPropsWithoutAnnotation ? true : false; >ExtractPropsMatch : true diff --git a/tests/baselines/reference/recursiveTupleTypeInference.errors.txt b/tests/baselines/reference/recursiveTupleTypeInference.errors.txt index 53ed377d2b7..f9fbfce896a 100644 --- a/tests/baselines/reference/recursiveTupleTypeInference.errors.txt +++ b/tests/baselines/reference/recursiveTupleTypeInference.errors.txt @@ -1,7 +1,7 @@ tests/cases/compiler/recursiveTupleTypeInference.ts(23,5): error TS2345: Argument of type '{ b: A; }' is not assignable to parameter of type 'G<{ b: unknown; }>'. Types of property 'b' are incompatible. - Type 'A' is not assignable to type '[[[[[[[[[[[[any, "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"]'. - Type 'string' is not assignable to type '[[[[[[[[[[[[any, "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"]'. + Type 'A' is not assignable to type '[never, "null"]'. + Type 'string' is not assignable to type '[never, "null"]'. ==== tests/cases/compiler/recursiveTupleTypeInference.ts (1 errors) ==== @@ -31,6 +31,6 @@ tests/cases/compiler/recursiveTupleTypeInference.ts(23,5): error TS2345: Argumen ~~ !!! error TS2345: Argument of type '{ b: A; }' is not assignable to parameter of type 'G<{ b: unknown; }>'. !!! error TS2345: Types of property 'b' are incompatible. -!!! error TS2345: Type 'A' is not assignable to type '[[[[[[[[[[[[any, "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"]'. -!!! error TS2345: Type 'string' is not assignable to type '[[[[[[[[[[[[any, "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"]'. +!!! error TS2345: Type 'A' is not assignable to type '[never, "null"]'. +!!! error TS2345: Type 'string' is not assignable to type '[never, "null"]'. \ No newline at end of file diff --git a/tests/baselines/reference/simplifyingConditionalWithInteriorConditionalIsRelated.types b/tests/baselines/reference/simplifyingConditionalWithInteriorConditionalIsRelated.types index 52e8ef8f14f..d9b814a2274 100644 --- a/tests/baselines/reference/simplifyingConditionalWithInteriorConditionalIsRelated.types +++ b/tests/baselines/reference/simplifyingConditionalWithInteriorConditionalIsRelated.types @@ -15,7 +15,7 @@ function JustConditional(): ConditionalType { >JustConditional : () => ConditionalType return ConditionalOrUndefined()!; // shouldn't error ->ConditionalOrUndefined()! : NonNullable> +>ConditionalOrUndefined()! : ConditionalType >ConditionalOrUndefined() : ConditionalType | undefined >ConditionalOrUndefined : () => ConditionalType | undefined } diff --git a/tests/baselines/reference/spreadObjectOrFalsy.js b/tests/baselines/reference/spreadObjectOrFalsy.js index 9aae56dc085..c7fcb4fb13b 100644 --- a/tests/baselines/reference/spreadObjectOrFalsy.js +++ b/tests/baselines/reference/spreadObjectOrFalsy.js @@ -111,7 +111,7 @@ declare function f5(a: S | T): S | T; declare function f6(a: T): T; declare function g1(a: A): (T | undefined) & T; +}>(a: A): T | (undefined & T); interface DatafulFoo { data: T; } diff --git a/tests/baselines/reference/spreadObjectOrFalsy.types b/tests/baselines/reference/spreadObjectOrFalsy.types index 1b9d54512e9..71e0d59f24a 100644 --- a/tests/baselines/reference/spreadObjectOrFalsy.types +++ b/tests/baselines/reference/spreadObjectOrFalsy.types @@ -56,19 +56,19 @@ function f6(a: T) { // Repro from #46976 function g1(a: A) { ->g1 : (a: A) => (T | undefined) & T ->z : (T | undefined) & T +>g1 : (a: A) => T | (undefined & T) +>z : T | (undefined & T) >a : A const { z } = a; ->z : (T | undefined) & T +>z : T | (undefined & T) >a : A return { ->{ ...z } : (T | undefined) & T +>{ ...z } : T | (undefined & T) ...z ->z : (T | undefined) & T +>z : T | (undefined & T) }; } @@ -98,9 +98,9 @@ class Foo { this.data.toLocaleLowerCase(); >this.data.toLocaleLowerCase() : string >this.data.toLocaleLowerCase : (locales?: string | string[] | undefined) => string ->this.data : (T | undefined) & T +>this.data : T | (undefined & T) >this : this & DatafulFoo ->data : (T | undefined) & T +>data : T | (undefined & T) >toLocaleLowerCase : (locales?: string | string[] | undefined) => string } } diff --git a/tests/baselines/reference/strictNullNotNullIndexTypeNoLib.errors.txt b/tests/baselines/reference/strictNullNotNullIndexTypeNoLib.errors.txt index 59e104ecd5c..9f4651b07c3 100644 --- a/tests/baselines/reference/strictNullNotNullIndexTypeNoLib.errors.txt +++ b/tests/baselines/reference/strictNullNotNullIndexTypeNoLib.errors.txt @@ -6,7 +6,6 @@ error TS2318: Cannot find global type 'Number'. error TS2318: Cannot find global type 'Object'. error TS2318: Cannot find global type 'RegExp'. error TS2318: Cannot find global type 'String'. -tests/cases/compiler/strictNullNotNullIndexTypeNoLib.ts(10,28): error TS2339: Property 'name' does not exist on type 'T["params"]'. !!! error TS2318: Cannot find global type 'Array'. @@ -17,7 +16,7 @@ tests/cases/compiler/strictNullNotNullIndexTypeNoLib.ts(10,28): error TS2339: Pr !!! error TS2318: Cannot find global type 'Object'. !!! error TS2318: Cannot find global type 'RegExp'. !!! error TS2318: Cannot find global type 'String'. -==== tests/cases/compiler/strictNullNotNullIndexTypeNoLib.ts (1 errors) ==== +==== tests/cases/compiler/strictNullNotNullIndexTypeNoLib.ts (0 errors) ==== type Readonly = {readonly [K in keyof T]: T[K]} interface A { params?: { name: string; }; @@ -28,8 +27,6 @@ tests/cases/compiler/strictNullNotNullIndexTypeNoLib.ts(10,28): error TS2339: Pr m() { this.attrs.params!.name; - ~~~~ -!!! error TS2339: Property 'name' does not exist on type 'T["params"]'. } } diff --git a/tests/baselines/reference/strictNullNotNullIndexTypeNoLib.symbols b/tests/baselines/reference/strictNullNotNullIndexTypeNoLib.symbols index 04e7779df13..a41798f2f52 100644 --- a/tests/baselines/reference/strictNullNotNullIndexTypeNoLib.symbols +++ b/tests/baselines/reference/strictNullNotNullIndexTypeNoLib.symbols @@ -29,11 +29,13 @@ class Test { >m : Symbol(Test.m, Decl(strictNullNotNullIndexTypeNoLib.ts, 6, 23)) this.attrs.params!.name; +>this.attrs.params!.name : Symbol(name, Decl(strictNullNotNullIndexTypeNoLib.ts, 2, 14)) >this.attrs.params : Symbol(params, Decl(strictNullNotNullIndexTypeNoLib.ts, 1, 13)) >this.attrs : Symbol(Test.attrs, Decl(strictNullNotNullIndexTypeNoLib.ts, 5, 25)) >this : Symbol(Test, Decl(strictNullNotNullIndexTypeNoLib.ts, 3, 1)) >attrs : Symbol(Test.attrs, Decl(strictNullNotNullIndexTypeNoLib.ts, 5, 25)) >params : Symbol(params, Decl(strictNullNotNullIndexTypeNoLib.ts, 1, 13)) +>name : Symbol(name, Decl(strictNullNotNullIndexTypeNoLib.ts, 2, 14)) } } diff --git a/tests/baselines/reference/strictNullNotNullIndexTypeNoLib.types b/tests/baselines/reference/strictNullNotNullIndexTypeNoLib.types index 773b37039db..aa2a723b091 100644 --- a/tests/baselines/reference/strictNullNotNullIndexTypeNoLib.types +++ b/tests/baselines/reference/strictNullNotNullIndexTypeNoLib.types @@ -18,14 +18,14 @@ class Test { >m : () => void this.attrs.params!.name; ->this.attrs.params!.name : any ->this.attrs.params! : T["params"] +>this.attrs.params!.name : string +>this.attrs.params! : T["params"] & {} >this.attrs.params : T["params"] | undefined >this.attrs : Readonly >this : this >attrs : Readonly >params : T["params"] | undefined ->name : any +>name : string } } @@ -62,10 +62,10 @@ class Test2 { >attrs : Readonly m() { ->m : () => T["params"] +>m : () => T["params"] & {} return this.attrs.params!; // Return type should maintain relationship with `T` after being not-null-asserted, ideally ->this.attrs.params! : T["params"] +>this.attrs.params! : T["params"] & {} >this.attrs.params : T["params"] | undefined >this.attrs : Readonly >this : this diff --git a/tests/baselines/reference/strictOptionalProperties1.types b/tests/baselines/reference/strictOptionalProperties1.types index ba14aedfd18..ae5ccf531ca 100644 --- a/tests/baselines/reference/strictOptionalProperties1.types +++ b/tests/baselines/reference/strictOptionalProperties1.types @@ -653,7 +653,7 @@ function expectNotUndefined(value: Undefinable): T { >'value is undefined' : "value is undefined" } return value; ->value : T +>value : T & ({} | null) } interface Bar { diff --git a/tests/baselines/reference/templateLiteralIntersection.types b/tests/baselines/reference/templateLiteralIntersection.types index b305f667774..0c716d40a73 100644 --- a/tests/baselines/reference/templateLiteralIntersection.types +++ b/tests/baselines/reference/templateLiteralIntersection.types @@ -54,7 +54,7 @@ type E = `${A & {}}`; >E : "a" type MixE = E & {} ->MixE : "a" & {} +>MixE : "a" type OriginE = `${MixE}` >OriginE : "a" diff --git a/tests/baselines/reference/templateLiteralTypes4.errors.txt b/tests/baselines/reference/templateLiteralTypes4.errors.txt new file mode 100644 index 00000000000..57a17a37b0e --- /dev/null +++ b/tests/baselines/reference/templateLiteralTypes4.errors.txt @@ -0,0 +1,313 @@ +tests/cases/conformance/types/literal/templateLiteralTypes4.ts(285,12): error TS2345: Argument of type '2' is not assignable to parameter of type '0 | 1'. +tests/cases/conformance/types/literal/templateLiteralTypes4.ts(289,12): error TS2345: Argument of type '2' is not assignable to parameter of type '0 | 1'. + + +==== tests/cases/conformance/types/literal/templateLiteralTypes4.ts (2 errors) ==== + // infer from number + type TNumber0 = "100" extends `${infer N extends number}` ? N : never; // 100 + type TNumber1 = "-100" extends `${infer N extends number}` ? N : never; // -100 + type TNumber2 = "1.1" extends `${infer N extends number}` ? N : never; // 1.1 + type TNumber3 = "8e-11" extends `${infer N extends number}` ? N : never; // 8e-11 (0.00000000008) + type TNumber4 = "0x10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) + type TNumber5 = "0o10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) + type TNumber6 = "0b10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) + type TNumber7 = "10e2" extends `${infer N extends number}` ? N : never; // number (not round-trippable) + type TNumber8 = "abcd" extends `${infer N extends number}` ? N : never; // never + + // infer from bigint + type TBigInt0 = "100" extends `${infer N extends bigint}` ? N : never; // 100n + type TBigInt1 = "-100" extends `${infer N extends bigint}` ? N : never; // -100n + type TBigInt2 = "0x10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) + type TBigInt3 = "0o10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) + type TBigInt4 = "0b10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) + type TBigInt5 = "1.1" extends `${infer N extends bigint}` ? N : never; // never + type TBigInt6 = "10e2" extends `${infer N extends bigint}` ? N : never; // never + type TBigInt7 = "abcd" extends `${infer N extends bigint}` ? N : never; // never + + // infer from boolean + type TBoolean0 = "true" extends `${infer T extends boolean}` ? T : never; // true + type TBoolean1 = "false" extends `${infer T extends boolean}` ? T : never; // false + type TBoolean2 = "abcd" extends `${infer T extends boolean}` ? T : never; // never + + // infer from null + type TNull0 = "null" extends `${infer T extends null}` ? T : never; // null + type TNull1 = "abcd" extends `${infer T extends null}` ? T : never; // never + + // infer from undefined + type TUndefined0 = "undefined" extends `${infer T extends undefined}` ? T : never; // undefined + type TUndefined1 = "abcd" extends `${infer T extends undefined}` ? T : never; // never + + // infer from literal enums + const enum StringLiteralEnum { Zero = "0", True = "true", False = "false", Undefined = "undefined", Null = "null" } + type TStringLiteralEnum0 = "0" extends `${infer T extends StringLiteralEnum}` ? T : never; // StringLiteralEnum.Zero + + const enum NumberLiteralEnum { Zero, One } + type TNumberLiteralEnum0 = "0" extends `${infer T extends NumberLiteralEnum}` ? T : never; // NumberLiteralEnum.Zero + + // infer from non-literal enums + const enum NonLiteralEnum { Zero = NumberLiteralEnum.Zero, One = NumberLiteralEnum.One } + type TNonLiteralEnum0 = "0" extends `${infer T extends NonLiteralEnum}` ? T : never; // 0 + + // infer using priority: + // string > template-literal > (string-literal | string-literal-enum) > + // number > enum > (number-literal | number-literal-enum) > + // bigint > bigint-literal > + // boolean > (boolean-literal | undefined | null) + + // #region string + // string > string-literal-enum + type PString00 = "0" extends `${infer T extends string | StringLiteralEnum}` ? T : never; // "0" + + // string > number + type PString01 = "0" extends `${infer T extends string | number}` ? T : never; // "0" + + // string > enum + type PString02 = "0" extends `${infer T extends string | NonLiteralEnum}` ? T : never; // "0" + + // string > (number-literal | number-literal-enum) + type PString03 = "0" extends `${infer T extends string | 0}` ? T : never; // "0" + type PString04 = "0" extends `${infer T extends string | NumberLiteralEnum}` ? T : never; // "0" + + // string > bigint + type PString05 = "0" extends `${infer T extends string | bigint}` ? T : never; // "0" + + // string > bigint-literal + type PString06 = "0" extends `${infer T extends string | 0n}` ? T : never; // "0" + + // string > boolean + type PString07 = "true" extends `${infer T extends string | boolean}` ? T : never; // "true" + type PString08 = "false" extends `${infer T extends string | boolean}` ? T : never; // "false" + + // string > (boolean-literal | undefined | null) + type PString09 = "true" extends `${infer T extends string | true}` ? T : never; // "true" + type PString10 = "false" extends `${infer T extends string | false}` ? T : never; // "false" + type PString11 = "undefined" extends `${infer T extends string | undefined}` ? T : never; // "undefined" + type PString12 = "null" extends `${infer T extends string | null}` ? T : never; // "null" + // #endregion string + + // #region template-literal + // template-literal > number + type PTemplate00 = "10" extends `${infer T extends `1${string}` | number}` ? T : never; // "10" + + // template-literal > enum + type PTemplate01 = "10" extends `${infer T extends `1${string}` | NonLiteralEnum}` ? T : never; // "10" + + // template-literal > (number-literal | number-literal-enum) + type PTemplate02 = "10" extends `${infer T extends `1${string}` | 10}` ? T : never; // "10" + type PTemplate03 = "10" extends `${infer T extends `1${string}` | NumberLiteralEnum}` ? T : never; // "10" + + // template-literal > bigint + type PTemplate04 = "10" extends `${infer T extends `1${string}` | bigint}` ? T : never; // "10" + + // template-literal > bigint-literal + type PTemplate05 = "10" extends `${infer T extends `1${string}` | 10n}` ? T : never; // "10" + + // template-literal > boolean + type PTemplate06 = "true" extends `${infer T extends `${string}e` | boolean}` ? T : never; // "true" + type PTemplate07 = "false" extends `${infer T extends `${string}e` | boolean}` ? T : never; // "false" + + // template-literal > (boolean-literal | undefined | null) + type PTemplate08 = "true" extends `${infer T extends `${"t"}${string}` | true}` ? T : never; // "true" + type PTemplate09 = "false" extends `${infer T extends `${"f"}${string}` | false}` ? T : never; // "false" + type PTemplate10 = "undefined" extends `${infer T extends `${"u"}${string}` | undefined}` ? T : never; // "undefined" + type PTemplate11 = "null" extends `${infer T extends `${"n"}${string}` | null}` ? T : never; // "null" + // #endregion template-literal + + // #region string-literal + // string-literal > number + type PStringLiteral00 = "0" extends `${infer T extends "0" | number}` ? T : never; // "0" + + // string-literal > enum + type PStringLiteral01 = "0" extends `${infer T extends "0" | NonLiteralEnum}` ? T : never; // "0" + + // string-literal > (number-literal | number-literal-enum) + type PStringLiteral02 = "0" extends `${infer T extends "0" | 0}` ? T : never; // "0" + type PStringLiteral03 = "0" extends `${infer T extends "0" | NumberLiteralEnum}` ? T : never; // "0" + + // string-literal > bigint + type PStringLiteral04 = "0" extends `${infer T extends "0" | bigint}` ? T : never; // "0" + + // string-literal > bigint-literal + type PStringLiteral05 = "0" extends `${infer T extends "0" | 0n}` ? T : never; // "0" + + // string-literal > boolean + type PStringLiteral06 = "true" extends `${infer T extends "true" | "false" | boolean}` ? T : never; // "true" + type PStringLiteral07 = "false" extends `${infer T extends "true" | "false" | boolean}` ? T : never; // "false" + + // string-literal > (boolean-literal | undefined | null) + type PStringLiteral08 = "true" extends `${infer T extends "true" | true}` ? T : never; // "true" + type PStringLiteral09 = "false" extends `${infer T extends "false" | false}` ? T : never; // "false" + type PStringLiteral10 = "undefined" extends `${infer T extends "undefined" | undefined}` ? T : never; // "undefined" + type PStringLiteral11 = "null" extends `${infer T extends "null" | null}` ? T : never; // "null" + // #endregion string-literal + + // #region string-literal-enum + // string-literal-enum > number + type PStringLiteralEnum00 = "0" extends `${infer T extends StringLiteralEnum | number}` ? T : never; // StringLiteralEnum.Zero + + // string-literal-enum > enum + type PStringLiteralEnum01 = "0" extends `${infer T extends StringLiteralEnum | NonLiteralEnum}` ? T : never; // StringLiteralEnum.Zero + + // string-literal-enum > (number-literal | number-literal-enum) + type PStringLiteralEnum02 = "0" extends `${infer T extends StringLiteralEnum | 0}` ? T : never; // StringLiteralEnum.Zero + type PStringLiteralEnum03 = "0" extends `${infer T extends StringLiteralEnum | NumberLiteralEnum}` ? T : never; // StringLiteralEnum.Zero + + // string-literal-enum > bigint + type PStringLiteralEnum04 = "0" extends `${infer T extends StringLiteralEnum | bigint}` ? T : never; // StringLiteralEnum.Zero + + // string-literal-enum > bigint-literal + type PStringLiteralEnum05 = "0" extends `${infer T extends StringLiteralEnum | 0n}` ? T : never; // StringLiteralEnum.Zero + + // string-literal-enum > boolean + type PStringLiteralEnum06 = "true" extends `${infer T extends StringLiteralEnum | boolean}` ? T : never; // StringLiteralEnum.True + type PStringLiteralEnum07 = "false" extends `${infer T extends StringLiteralEnum | boolean}` ? T : never; // StringLiteralEnum.False + + // string-literal-enum > (boolean-literal | undefined | null) + type PStringLiteralEnum08 = "true" extends `${infer T extends StringLiteralEnum | true}` ? T : never; // StringLiteralEnum.True + type PStringLiteralEnum09 = "false" extends `${infer T extends StringLiteralEnum | false}` ? T : never; // StringLiteralEnum.False + type PStringLiteralEnum10 = "undefined" extends `${infer T extends StringLiteralEnum | undefined}` ? T : never; // StringLiteralEnum.Undefined + type PStringLiteralEnum11 = "null" extends `${infer T extends StringLiteralEnum | null}` ? T : never; // StringLiteralEnum.Null + // #endregion string-literal-enum + + // #region number + // number > enum + type PNumber0 = "0" extends `${infer T extends number | NonLiteralEnum}` ? T : never; // 0 + + // number > number-literal-enum + type PNumber1 = "0" extends `${infer T extends number | NumberLiteralEnum}` ? T : never; // 0 + + // number > bigint + type PNumber2 = "0" extends `${infer T extends number | bigint}` ? T : never; // 0 + + // number > bigint-literal + type PNumber3 = "0" extends `${infer T extends number | 0n}` ? T : never; // 0 + // #endregion number + + // #region enum + // enum > number-literal-enum + type PEnum0 = "0" extends `${infer T extends NonLiteralEnum | NumberLiteralEnum}` ? T : never; // 0 + + // enum > bigint + type PEnum1 = "0" extends `${infer T extends NonLiteralEnum | bigint}` ? T : never; // 0 + + // enum > bigint-literal + type PEnum2 = "0" extends `${infer T extends NonLiteralEnum | 0n}` ? T : never; // 0 + // #endregion enum + + // #region number-literal + // number-literal > bigint + type PNumberLiteral0 = "0" extends `${infer T extends 0 | bigint}` ? T : never; // 0 + + // number-literal > bigint-literal + type PNumberLiteral1 = "0" extends `${infer T extends 0 | 0n}` ? T : never; // 0 + // #endregion number-literal + + // #region number-literal-enum + // number-literal-enum > bigint + type PNumberLiteralEnum0 = "0" extends `${infer T extends NumberLiteralEnum | bigint}` ? T : never; // NumberLiteralEnum.Zero + + // number-literal-enum > bigint-literal + type PNumberLiteralEnum1 = "0" extends `${infer T extends NumberLiteralEnum | 0n}` ? T : never; // NumberLiteralEnum.Zero + // #endregion number-literal-enum + + // non-matchable constituents are excluded + type PExclude0 = "0" extends `${infer T extends "1" | number}` ? T : never; // 0 + type PExclude1 = "0" extends `${infer T extends `1${string}` | number}` ? T : never; // 0 + type PExclude2 = "0" extends `${infer T extends 1 | bigint}` ? T : never; // 0n + type PExclude3 = "0" extends `${infer T extends NumberLiteralEnum.One | bigint}` ? T : never; // 0n + type PExclude4 = "100000000000000000000000" extends `${infer T extends number | bigint}` ? T : never; // 100000000000000000000000n + + // infer to prefix from string + type TPrefix0 = "100" extends `${infer T extends number}${string}` ? T : never; // 1 + type TPrefix1 = "trueabc" extends `${infer T extends boolean}${string}` ? T : never; // boolean (T only receives 't', not the whole string) + type TPrefix2 = `100:${string}` extends `${infer T extends number}:${string}` ? T : never; // 100 (T receives '100' because it scans until ':') + + // can use union w/multiple branches to extract each possibility + type ExtractPrimitives = + | T + | (T extends `${infer U extends number}` ? U : never) + | (T extends `${infer U extends bigint}` ? U : never) + | (T extends `${infer U extends boolean | null | undefined}` ? U : never) + ; + + type TExtract0 = ExtractPrimitives<"100">; // "100" | 100 | 100n + type TExtract1 = ExtractPrimitives<"1.1">; // "1.1" | 1.1 + type TExtract2 = ExtractPrimitives<"true">; // "true" | true + + + + // example use case (based on old TypedObjects proposal): + + // Use constrained `infer` in template literal to get ordinal indices as numbers: + type IndexFor = S extends `${infer N extends number}` ? N : never; + type IndicesOf = IndexFor>; // ordinal indices as number literals + + interface FieldDefinition { + readonly name: string; + readonly type: "i8" | "i16" | "i32" | "i64" | "u8" | "u16" | "u32" | "u64" | "f32" | "f64"; + } + + type FieldType = + T extends "i8" | "i16" | "i32" | "u8" | "u16" | "u32" | "f32" | "f64" ? number : + T extends "f32" | "f64" ? bigint : + never; + + // Generates named members like `{ x: number, y: bigint }` from `[{ name: "x", type: "i32" }, { name: "y", type: "i64" }]` + type TypedObjectNamedMembers = { + [P in TDef[number]["name"]]: FieldType["type"]>; + }; + + // Generates ordinal members like `{ 0: number, 1: bigint }` from `[{ name: "x", type: "i32" }, { name: "y", type: "i64" }]` + type TypedObjectOrdinalMembers = { + [I in Extract]: FieldType["type"]>; + }; + + // Default members + interface TypedObjectMembers { + // get/set a field by name + get(key: K): FieldType["type"]>; + set(key: K, value: FieldType["type"]>): void; + + // get/set a field by index + getIndex>(index: I): FieldType["type"]>; + setIndex>(index: I, value: FieldType["type"]>): void; + } + + type TypedObject = + & TypedObjectMembers + & TypedObjectNamedMembers + & TypedObjectOrdinalMembers; + + // NOTE: type would normally be created from something like `const Point = TypedObject([...])` from which we would infer the type + type Point = TypedObject<[ + { name: "x", type: "f64" }, + { name: "y", type: "f64" }, + ]>; + + declare const p: Point; + p.getIndex(0); // ok, 0 is a valid index + p.getIndex(1); // ok, 1 is a valid index + p.getIndex(2); // error, 2 is not a valid index + ~ +!!! error TS2345: Argument of type '2' is not assignable to parameter of type '0 | 1'. + + p.setIndex(0, 0); // ok, 0 is a valid index + p.setIndex(1, 0); // ok, 1 is a valid index + p.setIndex(2, 3); // error, 2 is not a valid index + ~ +!!! error TS2345: Argument of type '2' is not assignable to parameter of type '0 | 1'. + + // function inference + declare function f1(s: `**${T}**`): T; + f1("**123**"); // "123" + + declare function f2(s: `**${T}**`): T; + f2("**123**"); // 123 + + declare function f3(s: `**${T}**`): T; + f3("**123**"); // 123n + + declare function f4(s: `**${T}**`): T; + f4("**true**"); // true | "true" + f4("**false**"); // false | "false" + \ No newline at end of file diff --git a/tests/baselines/reference/templateLiteralTypes4.js b/tests/baselines/reference/templateLiteralTypes4.js new file mode 100644 index 00000000000..00ef80ae379 --- /dev/null +++ b/tests/baselines/reference/templateLiteralTypes4.js @@ -0,0 +1,477 @@ +//// [templateLiteralTypes4.ts] +// infer from number +type TNumber0 = "100" extends `${infer N extends number}` ? N : never; // 100 +type TNumber1 = "-100" extends `${infer N extends number}` ? N : never; // -100 +type TNumber2 = "1.1" extends `${infer N extends number}` ? N : never; // 1.1 +type TNumber3 = "8e-11" extends `${infer N extends number}` ? N : never; // 8e-11 (0.00000000008) +type TNumber4 = "0x10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +type TNumber5 = "0o10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +type TNumber6 = "0b10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +type TNumber7 = "10e2" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +type TNumber8 = "abcd" extends `${infer N extends number}` ? N : never; // never + +// infer from bigint +type TBigInt0 = "100" extends `${infer N extends bigint}` ? N : never; // 100n +type TBigInt1 = "-100" extends `${infer N extends bigint}` ? N : never; // -100n +type TBigInt2 = "0x10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) +type TBigInt3 = "0o10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) +type TBigInt4 = "0b10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) +type TBigInt5 = "1.1" extends `${infer N extends bigint}` ? N : never; // never +type TBigInt6 = "10e2" extends `${infer N extends bigint}` ? N : never; // never +type TBigInt7 = "abcd" extends `${infer N extends bigint}` ? N : never; // never + +// infer from boolean +type TBoolean0 = "true" extends `${infer T extends boolean}` ? T : never; // true +type TBoolean1 = "false" extends `${infer T extends boolean}` ? T : never; // false +type TBoolean2 = "abcd" extends `${infer T extends boolean}` ? T : never; // never + +// infer from null +type TNull0 = "null" extends `${infer T extends null}` ? T : never; // null +type TNull1 = "abcd" extends `${infer T extends null}` ? T : never; // never + +// infer from undefined +type TUndefined0 = "undefined" extends `${infer T extends undefined}` ? T : never; // undefined +type TUndefined1 = "abcd" extends `${infer T extends undefined}` ? T : never; // never + +// infer from literal enums +const enum StringLiteralEnum { Zero = "0", True = "true", False = "false", Undefined = "undefined", Null = "null" } +type TStringLiteralEnum0 = "0" extends `${infer T extends StringLiteralEnum}` ? T : never; // StringLiteralEnum.Zero + +const enum NumberLiteralEnum { Zero, One } +type TNumberLiteralEnum0 = "0" extends `${infer T extends NumberLiteralEnum}` ? T : never; // NumberLiteralEnum.Zero + +// infer from non-literal enums +const enum NonLiteralEnum { Zero = NumberLiteralEnum.Zero, One = NumberLiteralEnum.One } +type TNonLiteralEnum0 = "0" extends `${infer T extends NonLiteralEnum}` ? T : never; // 0 + +// infer using priority: +// string > template-literal > (string-literal | string-literal-enum) > +// number > enum > (number-literal | number-literal-enum) > +// bigint > bigint-literal > +// boolean > (boolean-literal | undefined | null) + +// #region string +// string > string-literal-enum +type PString00 = "0" extends `${infer T extends string | StringLiteralEnum}` ? T : never; // "0" + +// string > number +type PString01 = "0" extends `${infer T extends string | number}` ? T : never; // "0" + +// string > enum +type PString02 = "0" extends `${infer T extends string | NonLiteralEnum}` ? T : never; // "0" + +// string > (number-literal | number-literal-enum) +type PString03 = "0" extends `${infer T extends string | 0}` ? T : never; // "0" +type PString04 = "0" extends `${infer T extends string | NumberLiteralEnum}` ? T : never; // "0" + +// string > bigint +type PString05 = "0" extends `${infer T extends string | bigint}` ? T : never; // "0" + +// string > bigint-literal +type PString06 = "0" extends `${infer T extends string | 0n}` ? T : never; // "0" + +// string > boolean +type PString07 = "true" extends `${infer T extends string | boolean}` ? T : never; // "true" +type PString08 = "false" extends `${infer T extends string | boolean}` ? T : never; // "false" + +// string > (boolean-literal | undefined | null) +type PString09 = "true" extends `${infer T extends string | true}` ? T : never; // "true" +type PString10 = "false" extends `${infer T extends string | false}` ? T : never; // "false" +type PString11 = "undefined" extends `${infer T extends string | undefined}` ? T : never; // "undefined" +type PString12 = "null" extends `${infer T extends string | null}` ? T : never; // "null" +// #endregion string + +// #region template-literal +// template-literal > number +type PTemplate00 = "10" extends `${infer T extends `1${string}` | number}` ? T : never; // "10" + +// template-literal > enum +type PTemplate01 = "10" extends `${infer T extends `1${string}` | NonLiteralEnum}` ? T : never; // "10" + +// template-literal > (number-literal | number-literal-enum) +type PTemplate02 = "10" extends `${infer T extends `1${string}` | 10}` ? T : never; // "10" +type PTemplate03 = "10" extends `${infer T extends `1${string}` | NumberLiteralEnum}` ? T : never; // "10" + +// template-literal > bigint +type PTemplate04 = "10" extends `${infer T extends `1${string}` | bigint}` ? T : never; // "10" + +// template-literal > bigint-literal +type PTemplate05 = "10" extends `${infer T extends `1${string}` | 10n}` ? T : never; // "10" + +// template-literal > boolean +type PTemplate06 = "true" extends `${infer T extends `${string}e` | boolean}` ? T : never; // "true" +type PTemplate07 = "false" extends `${infer T extends `${string}e` | boolean}` ? T : never; // "false" + +// template-literal > (boolean-literal | undefined | null) +type PTemplate08 = "true" extends `${infer T extends `${"t"}${string}` | true}` ? T : never; // "true" +type PTemplate09 = "false" extends `${infer T extends `${"f"}${string}` | false}` ? T : never; // "false" +type PTemplate10 = "undefined" extends `${infer T extends `${"u"}${string}` | undefined}` ? T : never; // "undefined" +type PTemplate11 = "null" extends `${infer T extends `${"n"}${string}` | null}` ? T : never; // "null" +// #endregion template-literal + +// #region string-literal +// string-literal > number +type PStringLiteral00 = "0" extends `${infer T extends "0" | number}` ? T : never; // "0" + +// string-literal > enum +type PStringLiteral01 = "0" extends `${infer T extends "0" | NonLiteralEnum}` ? T : never; // "0" + +// string-literal > (number-literal | number-literal-enum) +type PStringLiteral02 = "0" extends `${infer T extends "0" | 0}` ? T : never; // "0" +type PStringLiteral03 = "0" extends `${infer T extends "0" | NumberLiteralEnum}` ? T : never; // "0" + +// string-literal > bigint +type PStringLiteral04 = "0" extends `${infer T extends "0" | bigint}` ? T : never; // "0" + +// string-literal > bigint-literal +type PStringLiteral05 = "0" extends `${infer T extends "0" | 0n}` ? T : never; // "0" + +// string-literal > boolean +type PStringLiteral06 = "true" extends `${infer T extends "true" | "false" | boolean}` ? T : never; // "true" +type PStringLiteral07 = "false" extends `${infer T extends "true" | "false" | boolean}` ? T : never; // "false" + +// string-literal > (boolean-literal | undefined | null) +type PStringLiteral08 = "true" extends `${infer T extends "true" | true}` ? T : never; // "true" +type PStringLiteral09 = "false" extends `${infer T extends "false" | false}` ? T : never; // "false" +type PStringLiteral10 = "undefined" extends `${infer T extends "undefined" | undefined}` ? T : never; // "undefined" +type PStringLiteral11 = "null" extends `${infer T extends "null" | null}` ? T : never; // "null" +// #endregion string-literal + +// #region string-literal-enum +// string-literal-enum > number +type PStringLiteralEnum00 = "0" extends `${infer T extends StringLiteralEnum | number}` ? T : never; // StringLiteralEnum.Zero + +// string-literal-enum > enum +type PStringLiteralEnum01 = "0" extends `${infer T extends StringLiteralEnum | NonLiteralEnum}` ? T : never; // StringLiteralEnum.Zero + +// string-literal-enum > (number-literal | number-literal-enum) +type PStringLiteralEnum02 = "0" extends `${infer T extends StringLiteralEnum | 0}` ? T : never; // StringLiteralEnum.Zero +type PStringLiteralEnum03 = "0" extends `${infer T extends StringLiteralEnum | NumberLiteralEnum}` ? T : never; // StringLiteralEnum.Zero + +// string-literal-enum > bigint +type PStringLiteralEnum04 = "0" extends `${infer T extends StringLiteralEnum | bigint}` ? T : never; // StringLiteralEnum.Zero + +// string-literal-enum > bigint-literal +type PStringLiteralEnum05 = "0" extends `${infer T extends StringLiteralEnum | 0n}` ? T : never; // StringLiteralEnum.Zero + +// string-literal-enum > boolean +type PStringLiteralEnum06 = "true" extends `${infer T extends StringLiteralEnum | boolean}` ? T : never; // StringLiteralEnum.True +type PStringLiteralEnum07 = "false" extends `${infer T extends StringLiteralEnum | boolean}` ? T : never; // StringLiteralEnum.False + +// string-literal-enum > (boolean-literal | undefined | null) +type PStringLiteralEnum08 = "true" extends `${infer T extends StringLiteralEnum | true}` ? T : never; // StringLiteralEnum.True +type PStringLiteralEnum09 = "false" extends `${infer T extends StringLiteralEnum | false}` ? T : never; // StringLiteralEnum.False +type PStringLiteralEnum10 = "undefined" extends `${infer T extends StringLiteralEnum | undefined}` ? T : never; // StringLiteralEnum.Undefined +type PStringLiteralEnum11 = "null" extends `${infer T extends StringLiteralEnum | null}` ? T : never; // StringLiteralEnum.Null +// #endregion string-literal-enum + +// #region number +// number > enum +type PNumber0 = "0" extends `${infer T extends number | NonLiteralEnum}` ? T : never; // 0 + +// number > number-literal-enum +type PNumber1 = "0" extends `${infer T extends number | NumberLiteralEnum}` ? T : never; // 0 + +// number > bigint +type PNumber2 = "0" extends `${infer T extends number | bigint}` ? T : never; // 0 + +// number > bigint-literal +type PNumber3 = "0" extends `${infer T extends number | 0n}` ? T : never; // 0 +// #endregion number + +// #region enum +// enum > number-literal-enum +type PEnum0 = "0" extends `${infer T extends NonLiteralEnum | NumberLiteralEnum}` ? T : never; // 0 + +// enum > bigint +type PEnum1 = "0" extends `${infer T extends NonLiteralEnum | bigint}` ? T : never; // 0 + +// enum > bigint-literal +type PEnum2 = "0" extends `${infer T extends NonLiteralEnum | 0n}` ? T : never; // 0 +// #endregion enum + +// #region number-literal +// number-literal > bigint +type PNumberLiteral0 = "0" extends `${infer T extends 0 | bigint}` ? T : never; // 0 + +// number-literal > bigint-literal +type PNumberLiteral1 = "0" extends `${infer T extends 0 | 0n}` ? T : never; // 0 +// #endregion number-literal + +// #region number-literal-enum +// number-literal-enum > bigint +type PNumberLiteralEnum0 = "0" extends `${infer T extends NumberLiteralEnum | bigint}` ? T : never; // NumberLiteralEnum.Zero + +// number-literal-enum > bigint-literal +type PNumberLiteralEnum1 = "0" extends `${infer T extends NumberLiteralEnum | 0n}` ? T : never; // NumberLiteralEnum.Zero +// #endregion number-literal-enum + +// non-matchable constituents are excluded +type PExclude0 = "0" extends `${infer T extends "1" | number}` ? T : never; // 0 +type PExclude1 = "0" extends `${infer T extends `1${string}` | number}` ? T : never; // 0 +type PExclude2 = "0" extends `${infer T extends 1 | bigint}` ? T : never; // 0n +type PExclude3 = "0" extends `${infer T extends NumberLiteralEnum.One | bigint}` ? T : never; // 0n +type PExclude4 = "100000000000000000000000" extends `${infer T extends number | bigint}` ? T : never; // 100000000000000000000000n + +// infer to prefix from string +type TPrefix0 = "100" extends `${infer T extends number}${string}` ? T : never; // 1 +type TPrefix1 = "trueabc" extends `${infer T extends boolean}${string}` ? T : never; // boolean (T only receives 't', not the whole string) +type TPrefix2 = `100:${string}` extends `${infer T extends number}:${string}` ? T : never; // 100 (T receives '100' because it scans until ':') + +// can use union w/multiple branches to extract each possibility +type ExtractPrimitives = + | T + | (T extends `${infer U extends number}` ? U : never) + | (T extends `${infer U extends bigint}` ? U : never) + | (T extends `${infer U extends boolean | null | undefined}` ? U : never) + ; + +type TExtract0 = ExtractPrimitives<"100">; // "100" | 100 | 100n +type TExtract1 = ExtractPrimitives<"1.1">; // "1.1" | 1.1 +type TExtract2 = ExtractPrimitives<"true">; // "true" | true + + + +// example use case (based on old TypedObjects proposal): + +// Use constrained `infer` in template literal to get ordinal indices as numbers: +type IndexFor = S extends `${infer N extends number}` ? N : never; +type IndicesOf = IndexFor>; // ordinal indices as number literals + +interface FieldDefinition { + readonly name: string; + readonly type: "i8" | "i16" | "i32" | "i64" | "u8" | "u16" | "u32" | "u64" | "f32" | "f64"; +} + +type FieldType = + T extends "i8" | "i16" | "i32" | "u8" | "u16" | "u32" | "f32" | "f64" ? number : + T extends "f32" | "f64" ? bigint : + never; + +// Generates named members like `{ x: number, y: bigint }` from `[{ name: "x", type: "i32" }, { name: "y", type: "i64" }]` +type TypedObjectNamedMembers = { + [P in TDef[number]["name"]]: FieldType["type"]>; +}; + +// Generates ordinal members like `{ 0: number, 1: bigint }` from `[{ name: "x", type: "i32" }, { name: "y", type: "i64" }]` +type TypedObjectOrdinalMembers = { + [I in Extract]: FieldType["type"]>; +}; + +// Default members +interface TypedObjectMembers { + // get/set a field by name + get(key: K): FieldType["type"]>; + set(key: K, value: FieldType["type"]>): void; + + // get/set a field by index + getIndex>(index: I): FieldType["type"]>; + setIndex>(index: I, value: FieldType["type"]>): void; +} + +type TypedObject = + & TypedObjectMembers + & TypedObjectNamedMembers + & TypedObjectOrdinalMembers; + +// NOTE: type would normally be created from something like `const Point = TypedObject([...])` from which we would infer the type +type Point = TypedObject<[ + { name: "x", type: "f64" }, + { name: "y", type: "f64" }, +]>; + +declare const p: Point; +p.getIndex(0); // ok, 0 is a valid index +p.getIndex(1); // ok, 1 is a valid index +p.getIndex(2); // error, 2 is not a valid index + +p.setIndex(0, 0); // ok, 0 is a valid index +p.setIndex(1, 0); // ok, 1 is a valid index +p.setIndex(2, 3); // error, 2 is not a valid index + +// function inference +declare function f1(s: `**${T}**`): T; +f1("**123**"); // "123" + +declare function f2(s: `**${T}**`): T; +f2("**123**"); // 123 + +declare function f3(s: `**${T}**`): T; +f3("**123**"); // 123n + +declare function f4(s: `**${T}**`): T; +f4("**true**"); // true | "true" +f4("**false**"); // false | "false" + + +//// [templateLiteralTypes4.js] +"use strict"; +p.getIndex(0); // ok, 0 is a valid index +p.getIndex(1); // ok, 1 is a valid index +p.getIndex(2); // error, 2 is not a valid index +p.setIndex(0, 0); // ok, 0 is a valid index +p.setIndex(1, 0); // ok, 1 is a valid index +p.setIndex(2, 3); // error, 2 is not a valid index +f1("**123**"); // "123" +f2("**123**"); // 123 +f3("**123**"); // 123n +f4("**true**"); // true | "true" +f4("**false**"); // false | "false" + + +//// [templateLiteralTypes4.d.ts] +declare type TNumber0 = "100" extends `${infer N extends number}` ? N : never; +declare type TNumber1 = "-100" extends `${infer N extends number}` ? N : never; +declare type TNumber2 = "1.1" extends `${infer N extends number}` ? N : never; +declare type TNumber3 = "8e-11" extends `${infer N extends number}` ? N : never; +declare type TNumber4 = "0x10" extends `${infer N extends number}` ? N : never; +declare type TNumber5 = "0o10" extends `${infer N extends number}` ? N : never; +declare type TNumber6 = "0b10" extends `${infer N extends number}` ? N : never; +declare type TNumber7 = "10e2" extends `${infer N extends number}` ? N : never; +declare type TNumber8 = "abcd" extends `${infer N extends number}` ? N : never; +declare type TBigInt0 = "100" extends `${infer N extends bigint}` ? N : never; +declare type TBigInt1 = "-100" extends `${infer N extends bigint}` ? N : never; +declare type TBigInt2 = "0x10" extends `${infer N extends bigint}` ? N : never; +declare type TBigInt3 = "0o10" extends `${infer N extends bigint}` ? N : never; +declare type TBigInt4 = "0b10" extends `${infer N extends bigint}` ? N : never; +declare type TBigInt5 = "1.1" extends `${infer N extends bigint}` ? N : never; +declare type TBigInt6 = "10e2" extends `${infer N extends bigint}` ? N : never; +declare type TBigInt7 = "abcd" extends `${infer N extends bigint}` ? N : never; +declare type TBoolean0 = "true" extends `${infer T extends boolean}` ? T : never; +declare type TBoolean1 = "false" extends `${infer T extends boolean}` ? T : never; +declare type TBoolean2 = "abcd" extends `${infer T extends boolean}` ? T : never; +declare type TNull0 = "null" extends `${infer T extends null}` ? T : never; +declare type TNull1 = "abcd" extends `${infer T extends null}` ? T : never; +declare type TUndefined0 = "undefined" extends `${infer T extends undefined}` ? T : never; +declare type TUndefined1 = "abcd" extends `${infer T extends undefined}` ? T : never; +declare const enum StringLiteralEnum { + Zero = "0", + True = "true", + False = "false", + Undefined = "undefined", + Null = "null" +} +declare type TStringLiteralEnum0 = "0" extends `${infer T extends StringLiteralEnum}` ? T : never; +declare const enum NumberLiteralEnum { + Zero = 0, + One = 1 +} +declare type TNumberLiteralEnum0 = "0" extends `${infer T extends NumberLiteralEnum}` ? T : never; +declare const enum NonLiteralEnum { + Zero = 0, + One = 1 +} +declare type TNonLiteralEnum0 = "0" extends `${infer T extends NonLiteralEnum}` ? T : never; +declare type PString00 = "0" extends `${infer T extends string | StringLiteralEnum}` ? T : never; +declare type PString01 = "0" extends `${infer T extends string | number}` ? T : never; +declare type PString02 = "0" extends `${infer T extends string | NonLiteralEnum}` ? T : never; +declare type PString03 = "0" extends `${infer T extends string | 0}` ? T : never; +declare type PString04 = "0" extends `${infer T extends string | NumberLiteralEnum}` ? T : never; +declare type PString05 = "0" extends `${infer T extends string | bigint}` ? T : never; +declare type PString06 = "0" extends `${infer T extends string | 0n}` ? T : never; +declare type PString07 = "true" extends `${infer T extends string | boolean}` ? T : never; +declare type PString08 = "false" extends `${infer T extends string | boolean}` ? T : never; +declare type PString09 = "true" extends `${infer T extends string | true}` ? T : never; +declare type PString10 = "false" extends `${infer T extends string | false}` ? T : never; +declare type PString11 = "undefined" extends `${infer T extends string | undefined}` ? T : never; +declare type PString12 = "null" extends `${infer T extends string | null}` ? T : never; +declare type PTemplate00 = "10" extends `${infer T extends `1${string}` | number}` ? T : never; +declare type PTemplate01 = "10" extends `${infer T extends `1${string}` | NonLiteralEnum}` ? T : never; +declare type PTemplate02 = "10" extends `${infer T extends `1${string}` | 10}` ? T : never; +declare type PTemplate03 = "10" extends `${infer T extends `1${string}` | NumberLiteralEnum}` ? T : never; +declare type PTemplate04 = "10" extends `${infer T extends `1${string}` | bigint}` ? T : never; +declare type PTemplate05 = "10" extends `${infer T extends `1${string}` | 10n}` ? T : never; +declare type PTemplate06 = "true" extends `${infer T extends `${string}e` | boolean}` ? T : never; +declare type PTemplate07 = "false" extends `${infer T extends `${string}e` | boolean}` ? T : never; +declare type PTemplate08 = "true" extends `${infer T extends `${"t"}${string}` | true}` ? T : never; +declare type PTemplate09 = "false" extends `${infer T extends `${"f"}${string}` | false}` ? T : never; +declare type PTemplate10 = "undefined" extends `${infer T extends `${"u"}${string}` | undefined}` ? T : never; +declare type PTemplate11 = "null" extends `${infer T extends `${"n"}${string}` | null}` ? T : never; +declare type PStringLiteral00 = "0" extends `${infer T extends "0" | number}` ? T : never; +declare type PStringLiteral01 = "0" extends `${infer T extends "0" | NonLiteralEnum}` ? T : never; +declare type PStringLiteral02 = "0" extends `${infer T extends "0" | 0}` ? T : never; +declare type PStringLiteral03 = "0" extends `${infer T extends "0" | NumberLiteralEnum}` ? T : never; +declare type PStringLiteral04 = "0" extends `${infer T extends "0" | bigint}` ? T : never; +declare type PStringLiteral05 = "0" extends `${infer T extends "0" | 0n}` ? T : never; +declare type PStringLiteral06 = "true" extends `${infer T extends "true" | "false" | boolean}` ? T : never; +declare type PStringLiteral07 = "false" extends `${infer T extends "true" | "false" | boolean}` ? T : never; +declare type PStringLiteral08 = "true" extends `${infer T extends "true" | true}` ? T : never; +declare type PStringLiteral09 = "false" extends `${infer T extends "false" | false}` ? T : never; +declare type PStringLiteral10 = "undefined" extends `${infer T extends "undefined" | undefined}` ? T : never; +declare type PStringLiteral11 = "null" extends `${infer T extends "null" | null}` ? T : never; +declare type PStringLiteralEnum00 = "0" extends `${infer T extends StringLiteralEnum | number}` ? T : never; +declare type PStringLiteralEnum01 = "0" extends `${infer T extends StringLiteralEnum | NonLiteralEnum}` ? T : never; +declare type PStringLiteralEnum02 = "0" extends `${infer T extends StringLiteralEnum | 0}` ? T : never; +declare type PStringLiteralEnum03 = "0" extends `${infer T extends StringLiteralEnum | NumberLiteralEnum}` ? T : never; +declare type PStringLiteralEnum04 = "0" extends `${infer T extends StringLiteralEnum | bigint}` ? T : never; +declare type PStringLiteralEnum05 = "0" extends `${infer T extends StringLiteralEnum | 0n}` ? T : never; +declare type PStringLiteralEnum06 = "true" extends `${infer T extends StringLiteralEnum | boolean}` ? T : never; +declare type PStringLiteralEnum07 = "false" extends `${infer T extends StringLiteralEnum | boolean}` ? T : never; +declare type PStringLiteralEnum08 = "true" extends `${infer T extends StringLiteralEnum | true}` ? T : never; +declare type PStringLiteralEnum09 = "false" extends `${infer T extends StringLiteralEnum | false}` ? T : never; +declare type PStringLiteralEnum10 = "undefined" extends `${infer T extends StringLiteralEnum | undefined}` ? T : never; +declare type PStringLiteralEnum11 = "null" extends `${infer T extends StringLiteralEnum | null}` ? T : never; +declare type PNumber0 = "0" extends `${infer T extends number | NonLiteralEnum}` ? T : never; +declare type PNumber1 = "0" extends `${infer T extends number | NumberLiteralEnum}` ? T : never; +declare type PNumber2 = "0" extends `${infer T extends number | bigint}` ? T : never; +declare type PNumber3 = "0" extends `${infer T extends number | 0n}` ? T : never; +declare type PEnum0 = "0" extends `${infer T extends NonLiteralEnum | NumberLiteralEnum}` ? T : never; +declare type PEnum1 = "0" extends `${infer T extends NonLiteralEnum | bigint}` ? T : never; +declare type PEnum2 = "0" extends `${infer T extends NonLiteralEnum | 0n}` ? T : never; +declare type PNumberLiteral0 = "0" extends `${infer T extends 0 | bigint}` ? T : never; +declare type PNumberLiteral1 = "0" extends `${infer T extends 0 | 0n}` ? T : never; +declare type PNumberLiteralEnum0 = "0" extends `${infer T extends NumberLiteralEnum | bigint}` ? T : never; +declare type PNumberLiteralEnum1 = "0" extends `${infer T extends NumberLiteralEnum | 0n}` ? T : never; +declare type PExclude0 = "0" extends `${infer T extends "1" | number}` ? T : never; +declare type PExclude1 = "0" extends `${infer T extends `1${string}` | number}` ? T : never; +declare type PExclude2 = "0" extends `${infer T extends 1 | bigint}` ? T : never; +declare type PExclude3 = "0" extends `${infer T extends NumberLiteralEnum.One | bigint}` ? T : never; +declare type PExclude4 = "100000000000000000000000" extends `${infer T extends number | bigint}` ? T : never; +declare type TPrefix0 = "100" extends `${infer T extends number}${string}` ? T : never; +declare type TPrefix1 = "trueabc" extends `${infer T extends boolean}${string}` ? T : never; +declare type TPrefix2 = `100:${string}` extends `${infer T extends number}:${string}` ? T : never; +declare type ExtractPrimitives = T | (T extends `${infer U extends number}` ? U : never) | (T extends `${infer U extends bigint}` ? U : never) | (T extends `${infer U extends boolean | null | undefined}` ? U : never); +declare type TExtract0 = ExtractPrimitives<"100">; +declare type TExtract1 = ExtractPrimitives<"1.1">; +declare type TExtract2 = ExtractPrimitives<"true">; +declare type IndexFor = S extends `${infer N extends number}` ? N : never; +declare type IndicesOf = IndexFor>; +interface FieldDefinition { + readonly name: string; + readonly type: "i8" | "i16" | "i32" | "i64" | "u8" | "u16" | "u32" | "u64" | "f32" | "f64"; +} +declare type FieldType = T extends "i8" | "i16" | "i32" | "u8" | "u16" | "u32" | "f32" | "f64" ? number : T extends "f32" | "f64" ? bigint : never; +declare type TypedObjectNamedMembers = { + [P in TDef[number]["name"]]: FieldType["type"]>; +}; +declare type TypedObjectOrdinalMembers = { + [I in Extract]: FieldType["type"]>; +}; +interface TypedObjectMembers { + get(key: K): FieldType["type"]>; + set(key: K, value: FieldType["type"]>): void; + getIndex>(index: I): FieldType["type"]>; + setIndex>(index: I, value: FieldType["type"]>): void; +} +declare type TypedObject = TypedObjectMembers & TypedObjectNamedMembers & TypedObjectOrdinalMembers; +declare type Point = TypedObject<[ + { + name: "x"; + type: "f64"; + }, + { + name: "y"; + type: "f64"; + } +]>; +declare const p: Point; +declare function f1(s: `**${T}**`): T; +declare function f2(s: `**${T}**`): T; +declare function f3(s: `**${T}**`): T; +declare function f4(s: `**${T}**`): T; diff --git a/tests/baselines/reference/templateLiteralTypes4.symbols b/tests/baselines/reference/templateLiteralTypes4.symbols new file mode 100644 index 00000000000..924812de013 --- /dev/null +++ b/tests/baselines/reference/templateLiteralTypes4.symbols @@ -0,0 +1,898 @@ +=== tests/cases/conformance/types/literal/templateLiteralTypes4.ts === +// infer from number +type TNumber0 = "100" extends `${infer N extends number}` ? N : never; // 100 +>TNumber0 : Symbol(TNumber0, Decl(templateLiteralTypes4.ts, 0, 0)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 1, 38)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 1, 38)) + +type TNumber1 = "-100" extends `${infer N extends number}` ? N : never; // -100 +>TNumber1 : Symbol(TNumber1, Decl(templateLiteralTypes4.ts, 1, 70)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 2, 39)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 2, 39)) + +type TNumber2 = "1.1" extends `${infer N extends number}` ? N : never; // 1.1 +>TNumber2 : Symbol(TNumber2, Decl(templateLiteralTypes4.ts, 2, 71)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 3, 38)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 3, 38)) + +type TNumber3 = "8e-11" extends `${infer N extends number}` ? N : never; // 8e-11 (0.00000000008) +>TNumber3 : Symbol(TNumber3, Decl(templateLiteralTypes4.ts, 3, 70)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 4, 40)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 4, 40)) + +type TNumber4 = "0x10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +>TNumber4 : Symbol(TNumber4, Decl(templateLiteralTypes4.ts, 4, 72)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 5, 39)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 5, 39)) + +type TNumber5 = "0o10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +>TNumber5 : Symbol(TNumber5, Decl(templateLiteralTypes4.ts, 5, 71)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 6, 39)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 6, 39)) + +type TNumber6 = "0b10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +>TNumber6 : Symbol(TNumber6, Decl(templateLiteralTypes4.ts, 6, 71)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 7, 39)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 7, 39)) + +type TNumber7 = "10e2" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +>TNumber7 : Symbol(TNumber7, Decl(templateLiteralTypes4.ts, 7, 71)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 8, 39)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 8, 39)) + +type TNumber8 = "abcd" extends `${infer N extends number}` ? N : never; // never +>TNumber8 : Symbol(TNumber8, Decl(templateLiteralTypes4.ts, 8, 71)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 9, 39)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 9, 39)) + +// infer from bigint +type TBigInt0 = "100" extends `${infer N extends bigint}` ? N : never; // 100n +>TBigInt0 : Symbol(TBigInt0, Decl(templateLiteralTypes4.ts, 9, 71)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 12, 38)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 12, 38)) + +type TBigInt1 = "-100" extends `${infer N extends bigint}` ? N : never; // -100n +>TBigInt1 : Symbol(TBigInt1, Decl(templateLiteralTypes4.ts, 12, 70)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 13, 39)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 13, 39)) + +type TBigInt2 = "0x10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) +>TBigInt2 : Symbol(TBigInt2, Decl(templateLiteralTypes4.ts, 13, 71)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 14, 39)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 14, 39)) + +type TBigInt3 = "0o10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) +>TBigInt3 : Symbol(TBigInt3, Decl(templateLiteralTypes4.ts, 14, 71)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 15, 39)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 15, 39)) + +type TBigInt4 = "0b10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) +>TBigInt4 : Symbol(TBigInt4, Decl(templateLiteralTypes4.ts, 15, 71)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 16, 39)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 16, 39)) + +type TBigInt5 = "1.1" extends `${infer N extends bigint}` ? N : never; // never +>TBigInt5 : Symbol(TBigInt5, Decl(templateLiteralTypes4.ts, 16, 71)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 17, 38)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 17, 38)) + +type TBigInt6 = "10e2" extends `${infer N extends bigint}` ? N : never; // never +>TBigInt6 : Symbol(TBigInt6, Decl(templateLiteralTypes4.ts, 17, 70)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 18, 39)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 18, 39)) + +type TBigInt7 = "abcd" extends `${infer N extends bigint}` ? N : never; // never +>TBigInt7 : Symbol(TBigInt7, Decl(templateLiteralTypes4.ts, 18, 71)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 19, 39)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 19, 39)) + +// infer from boolean +type TBoolean0 = "true" extends `${infer T extends boolean}` ? T : never; // true +>TBoolean0 : Symbol(TBoolean0, Decl(templateLiteralTypes4.ts, 19, 71)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 22, 40)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 22, 40)) + +type TBoolean1 = "false" extends `${infer T extends boolean}` ? T : never; // false +>TBoolean1 : Symbol(TBoolean1, Decl(templateLiteralTypes4.ts, 22, 73)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 23, 41)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 23, 41)) + +type TBoolean2 = "abcd" extends `${infer T extends boolean}` ? T : never; // never +>TBoolean2 : Symbol(TBoolean2, Decl(templateLiteralTypes4.ts, 23, 74)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 24, 40)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 24, 40)) + +// infer from null +type TNull0 = "null" extends `${infer T extends null}` ? T : never; // null +>TNull0 : Symbol(TNull0, Decl(templateLiteralTypes4.ts, 24, 73)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 27, 37)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 27, 37)) + +type TNull1 = "abcd" extends `${infer T extends null}` ? T : never; // never +>TNull1 : Symbol(TNull1, Decl(templateLiteralTypes4.ts, 27, 67)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 28, 37)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 28, 37)) + +// infer from undefined +type TUndefined0 = "undefined" extends `${infer T extends undefined}` ? T : never; // undefined +>TUndefined0 : Symbol(TUndefined0, Decl(templateLiteralTypes4.ts, 28, 67)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 31, 47)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 31, 47)) + +type TUndefined1 = "abcd" extends `${infer T extends undefined}` ? T : never; // never +>TUndefined1 : Symbol(TUndefined1, Decl(templateLiteralTypes4.ts, 31, 82)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 32, 42)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 32, 42)) + +// infer from literal enums +const enum StringLiteralEnum { Zero = "0", True = "true", False = "false", Undefined = "undefined", Null = "null" } +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>Zero : Symbol(StringLiteralEnum.Zero, Decl(templateLiteralTypes4.ts, 35, 30)) +>True : Symbol(StringLiteralEnum.True, Decl(templateLiteralTypes4.ts, 35, 42)) +>False : Symbol(StringLiteralEnum.False, Decl(templateLiteralTypes4.ts, 35, 57)) +>Undefined : Symbol(StringLiteralEnum.Undefined, Decl(templateLiteralTypes4.ts, 35, 74)) +>Null : Symbol(StringLiteralEnum.Null, Decl(templateLiteralTypes4.ts, 35, 99)) + +type TStringLiteralEnum0 = "0" extends `${infer T extends StringLiteralEnum}` ? T : never; // StringLiteralEnum.Zero +>TStringLiteralEnum0 : Symbol(TStringLiteralEnum0, Decl(templateLiteralTypes4.ts, 35, 115)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 36, 47)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 36, 47)) + +const enum NumberLiteralEnum { Zero, One } +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>Zero : Symbol(NumberLiteralEnum.Zero, Decl(templateLiteralTypes4.ts, 38, 30)) +>One : Symbol(NumberLiteralEnum.One, Decl(templateLiteralTypes4.ts, 38, 36)) + +type TNumberLiteralEnum0 = "0" extends `${infer T extends NumberLiteralEnum}` ? T : never; // NumberLiteralEnum.Zero +>TNumberLiteralEnum0 : Symbol(TNumberLiteralEnum0, Decl(templateLiteralTypes4.ts, 38, 42)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 39, 47)) +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 39, 47)) + +// infer from non-literal enums +const enum NonLiteralEnum { Zero = NumberLiteralEnum.Zero, One = NumberLiteralEnum.One } +>NonLiteralEnum : Symbol(NonLiteralEnum, Decl(templateLiteralTypes4.ts, 39, 90)) +>Zero : Symbol(NonLiteralEnum.Zero, Decl(templateLiteralTypes4.ts, 42, 27)) +>NumberLiteralEnum.Zero : Symbol(NumberLiteralEnum.Zero, Decl(templateLiteralTypes4.ts, 38, 30)) +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>Zero : Symbol(NumberLiteralEnum.Zero, Decl(templateLiteralTypes4.ts, 38, 30)) +>One : Symbol(NonLiteralEnum.One, Decl(templateLiteralTypes4.ts, 42, 58)) +>NumberLiteralEnum.One : Symbol(NumberLiteralEnum.One, Decl(templateLiteralTypes4.ts, 38, 36)) +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>One : Symbol(NumberLiteralEnum.One, Decl(templateLiteralTypes4.ts, 38, 36)) + +type TNonLiteralEnum0 = "0" extends `${infer T extends NonLiteralEnum}` ? T : never; // 0 +>TNonLiteralEnum0 : Symbol(TNonLiteralEnum0, Decl(templateLiteralTypes4.ts, 42, 88)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 43, 44)) +>NonLiteralEnum : Symbol(NonLiteralEnum, Decl(templateLiteralTypes4.ts, 39, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 43, 44)) + +// infer using priority: +// string > template-literal > (string-literal | string-literal-enum) > +// number > enum > (number-literal | number-literal-enum) > +// bigint > bigint-literal > +// boolean > (boolean-literal | undefined | null) + +// #region string +// string > string-literal-enum +type PString00 = "0" extends `${infer T extends string | StringLiteralEnum}` ? T : never; // "0" +>PString00 : Symbol(PString00, Decl(templateLiteralTypes4.ts, 43, 84)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 53, 37)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 53, 37)) + +// string > number +type PString01 = "0" extends `${infer T extends string | number}` ? T : never; // "0" +>PString01 : Symbol(PString01, Decl(templateLiteralTypes4.ts, 53, 89)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 56, 37)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 56, 37)) + +// string > enum +type PString02 = "0" extends `${infer T extends string | NonLiteralEnum}` ? T : never; // "0" +>PString02 : Symbol(PString02, Decl(templateLiteralTypes4.ts, 56, 78)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 59, 37)) +>NonLiteralEnum : Symbol(NonLiteralEnum, Decl(templateLiteralTypes4.ts, 39, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 59, 37)) + +// string > (number-literal | number-literal-enum) +type PString03 = "0" extends `${infer T extends string | 0}` ? T : never; // "0" +>PString03 : Symbol(PString03, Decl(templateLiteralTypes4.ts, 59, 86)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 62, 37)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 62, 37)) + +type PString04 = "0" extends `${infer T extends string | NumberLiteralEnum}` ? T : never; // "0" +>PString04 : Symbol(PString04, Decl(templateLiteralTypes4.ts, 62, 73)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 63, 37)) +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 63, 37)) + +// string > bigint +type PString05 = "0" extends `${infer T extends string | bigint}` ? T : never; // "0" +>PString05 : Symbol(PString05, Decl(templateLiteralTypes4.ts, 63, 89)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 66, 37)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 66, 37)) + +// string > bigint-literal +type PString06 = "0" extends `${infer T extends string | 0n}` ? T : never; // "0" +>PString06 : Symbol(PString06, Decl(templateLiteralTypes4.ts, 66, 78)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 69, 37)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 69, 37)) + +// string > boolean +type PString07 = "true" extends `${infer T extends string | boolean}` ? T : never; // "true" +>PString07 : Symbol(PString07, Decl(templateLiteralTypes4.ts, 69, 74)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 72, 40)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 72, 40)) + +type PString08 = "false" extends `${infer T extends string | boolean}` ? T : never; // "false" +>PString08 : Symbol(PString08, Decl(templateLiteralTypes4.ts, 72, 82)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 73, 41)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 73, 41)) + +// string > (boolean-literal | undefined | null) +type PString09 = "true" extends `${infer T extends string | true}` ? T : never; // "true" +>PString09 : Symbol(PString09, Decl(templateLiteralTypes4.ts, 73, 83)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 76, 40)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 76, 40)) + +type PString10 = "false" extends `${infer T extends string | false}` ? T : never; // "false" +>PString10 : Symbol(PString10, Decl(templateLiteralTypes4.ts, 76, 79)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 77, 41)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 77, 41)) + +type PString11 = "undefined" extends `${infer T extends string | undefined}` ? T : never; // "undefined" +>PString11 : Symbol(PString11, Decl(templateLiteralTypes4.ts, 77, 81)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 78, 45)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 78, 45)) + +type PString12 = "null" extends `${infer T extends string | null}` ? T : never; // "null" +>PString12 : Symbol(PString12, Decl(templateLiteralTypes4.ts, 78, 89)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 79, 40)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 79, 40)) + +// #endregion string + +// #region template-literal +// template-literal > number +type PTemplate00 = "10" extends `${infer T extends `1${string}` | number}` ? T : never; // "10" +>PTemplate00 : Symbol(PTemplate00, Decl(templateLiteralTypes4.ts, 79, 79)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 84, 40)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 84, 40)) + +// template-literal > enum +type PTemplate01 = "10" extends `${infer T extends `1${string}` | NonLiteralEnum}` ? T : never; // "10" +>PTemplate01 : Symbol(PTemplate01, Decl(templateLiteralTypes4.ts, 84, 87)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 87, 40)) +>NonLiteralEnum : Symbol(NonLiteralEnum, Decl(templateLiteralTypes4.ts, 39, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 87, 40)) + +// template-literal > (number-literal | number-literal-enum) +type PTemplate02 = "10" extends `${infer T extends `1${string}` | 10}` ? T : never; // "10" +>PTemplate02 : Symbol(PTemplate02, Decl(templateLiteralTypes4.ts, 87, 95)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 90, 40)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 90, 40)) + +type PTemplate03 = "10" extends `${infer T extends `1${string}` | NumberLiteralEnum}` ? T : never; // "10" +>PTemplate03 : Symbol(PTemplate03, Decl(templateLiteralTypes4.ts, 90, 83)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 91, 40)) +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 91, 40)) + +// template-literal > bigint +type PTemplate04 = "10" extends `${infer T extends `1${string}` | bigint}` ? T : never; // "10" +>PTemplate04 : Symbol(PTemplate04, Decl(templateLiteralTypes4.ts, 91, 98)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 94, 40)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 94, 40)) + +// template-literal > bigint-literal +type PTemplate05 = "10" extends `${infer T extends `1${string}` | 10n}` ? T : never; // "10" +>PTemplate05 : Symbol(PTemplate05, Decl(templateLiteralTypes4.ts, 94, 87)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 97, 40)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 97, 40)) + +// template-literal > boolean +type PTemplate06 = "true" extends `${infer T extends `${string}e` | boolean}` ? T : never; // "true" +>PTemplate06 : Symbol(PTemplate06, Decl(templateLiteralTypes4.ts, 97, 84)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 100, 42)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 100, 42)) + +type PTemplate07 = "false" extends `${infer T extends `${string}e` | boolean}` ? T : never; // "false" +>PTemplate07 : Symbol(PTemplate07, Decl(templateLiteralTypes4.ts, 100, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 101, 43)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 101, 43)) + +// template-literal > (boolean-literal | undefined | null) +type PTemplate08 = "true" extends `${infer T extends `${"t"}${string}` | true}` ? T : never; // "true" +>PTemplate08 : Symbol(PTemplate08, Decl(templateLiteralTypes4.ts, 101, 91)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 104, 42)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 104, 42)) + +type PTemplate09 = "false" extends `${infer T extends `${"f"}${string}` | false}` ? T : never; // "false" +>PTemplate09 : Symbol(PTemplate09, Decl(templateLiteralTypes4.ts, 104, 92)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 105, 43)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 105, 43)) + +type PTemplate10 = "undefined" extends `${infer T extends `${"u"}${string}` | undefined}` ? T : never; // "undefined" +>PTemplate10 : Symbol(PTemplate10, Decl(templateLiteralTypes4.ts, 105, 94)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 106, 47)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 106, 47)) + +type PTemplate11 = "null" extends `${infer T extends `${"n"}${string}` | null}` ? T : never; // "null" +>PTemplate11 : Symbol(PTemplate11, Decl(templateLiteralTypes4.ts, 106, 102)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 107, 42)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 107, 42)) + +// #endregion template-literal + +// #region string-literal +// string-literal > number +type PStringLiteral00 = "0" extends `${infer T extends "0" | number}` ? T : never; // "0" +>PStringLiteral00 : Symbol(PStringLiteral00, Decl(templateLiteralTypes4.ts, 107, 92)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 112, 44)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 112, 44)) + +// string-literal > enum +type PStringLiteral01 = "0" extends `${infer T extends "0" | NonLiteralEnum}` ? T : never; // "0" +>PStringLiteral01 : Symbol(PStringLiteral01, Decl(templateLiteralTypes4.ts, 112, 82)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 115, 44)) +>NonLiteralEnum : Symbol(NonLiteralEnum, Decl(templateLiteralTypes4.ts, 39, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 115, 44)) + +// string-literal > (number-literal | number-literal-enum) +type PStringLiteral02 = "0" extends `${infer T extends "0" | 0}` ? T : never; // "0" +>PStringLiteral02 : Symbol(PStringLiteral02, Decl(templateLiteralTypes4.ts, 115, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 118, 44)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 118, 44)) + +type PStringLiteral03 = "0" extends `${infer T extends "0" | NumberLiteralEnum}` ? T : never; // "0" +>PStringLiteral03 : Symbol(PStringLiteral03, Decl(templateLiteralTypes4.ts, 118, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 119, 44)) +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 119, 44)) + +// string-literal > bigint +type PStringLiteral04 = "0" extends `${infer T extends "0" | bigint}` ? T : never; // "0" +>PStringLiteral04 : Symbol(PStringLiteral04, Decl(templateLiteralTypes4.ts, 119, 93)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 122, 44)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 122, 44)) + +// string-literal > bigint-literal +type PStringLiteral05 = "0" extends `${infer T extends "0" | 0n}` ? T : never; // "0" +>PStringLiteral05 : Symbol(PStringLiteral05, Decl(templateLiteralTypes4.ts, 122, 82)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 125, 44)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 125, 44)) + +// string-literal > boolean +type PStringLiteral06 = "true" extends `${infer T extends "true" | "false" | boolean}` ? T : never; // "true" +>PStringLiteral06 : Symbol(PStringLiteral06, Decl(templateLiteralTypes4.ts, 125, 78)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 128, 47)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 128, 47)) + +type PStringLiteral07 = "false" extends `${infer T extends "true" | "false" | boolean}` ? T : never; // "false" +>PStringLiteral07 : Symbol(PStringLiteral07, Decl(templateLiteralTypes4.ts, 128, 99)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 129, 48)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 129, 48)) + +// string-literal > (boolean-literal | undefined | null) +type PStringLiteral08 = "true" extends `${infer T extends "true" | true}` ? T : never; // "true" +>PStringLiteral08 : Symbol(PStringLiteral08, Decl(templateLiteralTypes4.ts, 129, 100)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 132, 47)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 132, 47)) + +type PStringLiteral09 = "false" extends `${infer T extends "false" | false}` ? T : never; // "false" +>PStringLiteral09 : Symbol(PStringLiteral09, Decl(templateLiteralTypes4.ts, 132, 86)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 133, 48)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 133, 48)) + +type PStringLiteral10 = "undefined" extends `${infer T extends "undefined" | undefined}` ? T : never; // "undefined" +>PStringLiteral10 : Symbol(PStringLiteral10, Decl(templateLiteralTypes4.ts, 133, 89)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 134, 52)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 134, 52)) + +type PStringLiteral11 = "null" extends `${infer T extends "null" | null}` ? T : never; // "null" +>PStringLiteral11 : Symbol(PStringLiteral11, Decl(templateLiteralTypes4.ts, 134, 101)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 135, 47)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 135, 47)) + +// #endregion string-literal + +// #region string-literal-enum +// string-literal-enum > number +type PStringLiteralEnum00 = "0" extends `${infer T extends StringLiteralEnum | number}` ? T : never; // StringLiteralEnum.Zero +>PStringLiteralEnum00 : Symbol(PStringLiteralEnum00, Decl(templateLiteralTypes4.ts, 135, 86)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 140, 48)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 140, 48)) + +// string-literal-enum > enum +type PStringLiteralEnum01 = "0" extends `${infer T extends StringLiteralEnum | NonLiteralEnum}` ? T : never; // StringLiteralEnum.Zero +>PStringLiteralEnum01 : Symbol(PStringLiteralEnum01, Decl(templateLiteralTypes4.ts, 140, 100)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 143, 48)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>NonLiteralEnum : Symbol(NonLiteralEnum, Decl(templateLiteralTypes4.ts, 39, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 143, 48)) + +// string-literal-enum > (number-literal | number-literal-enum) +type PStringLiteralEnum02 = "0" extends `${infer T extends StringLiteralEnum | 0}` ? T : never; // StringLiteralEnum.Zero +>PStringLiteralEnum02 : Symbol(PStringLiteralEnum02, Decl(templateLiteralTypes4.ts, 143, 108)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 146, 48)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 146, 48)) + +type PStringLiteralEnum03 = "0" extends `${infer T extends StringLiteralEnum | NumberLiteralEnum}` ? T : never; // StringLiteralEnum.Zero +>PStringLiteralEnum03 : Symbol(PStringLiteralEnum03, Decl(templateLiteralTypes4.ts, 146, 95)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 147, 48)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 147, 48)) + +// string-literal-enum > bigint +type PStringLiteralEnum04 = "0" extends `${infer T extends StringLiteralEnum | bigint}` ? T : never; // StringLiteralEnum.Zero +>PStringLiteralEnum04 : Symbol(PStringLiteralEnum04, Decl(templateLiteralTypes4.ts, 147, 111)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 150, 48)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 150, 48)) + +// string-literal-enum > bigint-literal +type PStringLiteralEnum05 = "0" extends `${infer T extends StringLiteralEnum | 0n}` ? T : never; // StringLiteralEnum.Zero +>PStringLiteralEnum05 : Symbol(PStringLiteralEnum05, Decl(templateLiteralTypes4.ts, 150, 100)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 153, 48)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 153, 48)) + +// string-literal-enum > boolean +type PStringLiteralEnum06 = "true" extends `${infer T extends StringLiteralEnum | boolean}` ? T : never; // StringLiteralEnum.True +>PStringLiteralEnum06 : Symbol(PStringLiteralEnum06, Decl(templateLiteralTypes4.ts, 153, 96)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 156, 51)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 156, 51)) + +type PStringLiteralEnum07 = "false" extends `${infer T extends StringLiteralEnum | boolean}` ? T : never; // StringLiteralEnum.False +>PStringLiteralEnum07 : Symbol(PStringLiteralEnum07, Decl(templateLiteralTypes4.ts, 156, 104)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 157, 52)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 157, 52)) + +// string-literal-enum > (boolean-literal | undefined | null) +type PStringLiteralEnum08 = "true" extends `${infer T extends StringLiteralEnum | true}` ? T : never; // StringLiteralEnum.True +>PStringLiteralEnum08 : Symbol(PStringLiteralEnum08, Decl(templateLiteralTypes4.ts, 157, 105)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 160, 51)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 160, 51)) + +type PStringLiteralEnum09 = "false" extends `${infer T extends StringLiteralEnum | false}` ? T : never; // StringLiteralEnum.False +>PStringLiteralEnum09 : Symbol(PStringLiteralEnum09, Decl(templateLiteralTypes4.ts, 160, 101)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 161, 52)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 161, 52)) + +type PStringLiteralEnum10 = "undefined" extends `${infer T extends StringLiteralEnum | undefined}` ? T : never; // StringLiteralEnum.Undefined +>PStringLiteralEnum10 : Symbol(PStringLiteralEnum10, Decl(templateLiteralTypes4.ts, 161, 103)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 162, 56)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 162, 56)) + +type PStringLiteralEnum11 = "null" extends `${infer T extends StringLiteralEnum | null}` ? T : never; // StringLiteralEnum.Null +>PStringLiteralEnum11 : Symbol(PStringLiteralEnum11, Decl(templateLiteralTypes4.ts, 162, 111)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 163, 51)) +>StringLiteralEnum : Symbol(StringLiteralEnum, Decl(templateLiteralTypes4.ts, 32, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 163, 51)) + +// #endregion string-literal-enum + +// #region number +// number > enum +type PNumber0 = "0" extends `${infer T extends number | NonLiteralEnum}` ? T : never; // 0 +>PNumber0 : Symbol(PNumber0, Decl(templateLiteralTypes4.ts, 163, 101)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 168, 36)) +>NonLiteralEnum : Symbol(NonLiteralEnum, Decl(templateLiteralTypes4.ts, 39, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 168, 36)) + +// number > number-literal-enum +type PNumber1 = "0" extends `${infer T extends number | NumberLiteralEnum}` ? T : never; // 0 +>PNumber1 : Symbol(PNumber1, Decl(templateLiteralTypes4.ts, 168, 85)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 171, 36)) +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 171, 36)) + +// number > bigint +type PNumber2 = "0" extends `${infer T extends number | bigint}` ? T : never; // 0 +>PNumber2 : Symbol(PNumber2, Decl(templateLiteralTypes4.ts, 171, 88)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 174, 36)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 174, 36)) + +// number > bigint-literal +type PNumber3 = "0" extends `${infer T extends number | 0n}` ? T : never; // 0 +>PNumber3 : Symbol(PNumber3, Decl(templateLiteralTypes4.ts, 174, 77)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 177, 36)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 177, 36)) + +// #endregion number + +// #region enum +// enum > number-literal-enum +type PEnum0 = "0" extends `${infer T extends NonLiteralEnum | NumberLiteralEnum}` ? T : never; // 0 +>PEnum0 : Symbol(PEnum0, Decl(templateLiteralTypes4.ts, 177, 73)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 182, 34)) +>NonLiteralEnum : Symbol(NonLiteralEnum, Decl(templateLiteralTypes4.ts, 39, 90)) +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 182, 34)) + +// enum > bigint +type PEnum1 = "0" extends `${infer T extends NonLiteralEnum | bigint}` ? T : never; // 0 +>PEnum1 : Symbol(PEnum1, Decl(templateLiteralTypes4.ts, 182, 94)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 185, 34)) +>NonLiteralEnum : Symbol(NonLiteralEnum, Decl(templateLiteralTypes4.ts, 39, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 185, 34)) + +// enum > bigint-literal +type PEnum2 = "0" extends `${infer T extends NonLiteralEnum | 0n}` ? T : never; // 0 +>PEnum2 : Symbol(PEnum2, Decl(templateLiteralTypes4.ts, 185, 83)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 188, 34)) +>NonLiteralEnum : Symbol(NonLiteralEnum, Decl(templateLiteralTypes4.ts, 39, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 188, 34)) + +// #endregion enum + +// #region number-literal +// number-literal > bigint +type PNumberLiteral0 = "0" extends `${infer T extends 0 | bigint}` ? T : never; // 0 +>PNumberLiteral0 : Symbol(PNumberLiteral0, Decl(templateLiteralTypes4.ts, 188, 79)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 193, 43)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 193, 43)) + +// number-literal > bigint-literal +type PNumberLiteral1 = "0" extends `${infer T extends 0 | 0n}` ? T : never; // 0 +>PNumberLiteral1 : Symbol(PNumberLiteral1, Decl(templateLiteralTypes4.ts, 193, 79)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 196, 43)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 196, 43)) + +// #endregion number-literal + +// #region number-literal-enum +// number-literal-enum > bigint +type PNumberLiteralEnum0 = "0" extends `${infer T extends NumberLiteralEnum | bigint}` ? T : never; // NumberLiteralEnum.Zero +>PNumberLiteralEnum0 : Symbol(PNumberLiteralEnum0, Decl(templateLiteralTypes4.ts, 196, 75)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 201, 47)) +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 201, 47)) + +// number-literal-enum > bigint-literal +type PNumberLiteralEnum1 = "0" extends `${infer T extends NumberLiteralEnum | 0n}` ? T : never; // NumberLiteralEnum.Zero +>PNumberLiteralEnum1 : Symbol(PNumberLiteralEnum1, Decl(templateLiteralTypes4.ts, 201, 99)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 204, 47)) +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 204, 47)) + +// #endregion number-literal-enum + +// non-matchable constituents are excluded +type PExclude0 = "0" extends `${infer T extends "1" | number}` ? T : never; // 0 +>PExclude0 : Symbol(PExclude0, Decl(templateLiteralTypes4.ts, 204, 95)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 208, 37)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 208, 37)) + +type PExclude1 = "0" extends `${infer T extends `1${string}` | number}` ? T : never; // 0 +>PExclude1 : Symbol(PExclude1, Decl(templateLiteralTypes4.ts, 208, 75)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 209, 37)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 209, 37)) + +type PExclude2 = "0" extends `${infer T extends 1 | bigint}` ? T : never; // 0n +>PExclude2 : Symbol(PExclude2, Decl(templateLiteralTypes4.ts, 209, 84)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 210, 37)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 210, 37)) + +type PExclude3 = "0" extends `${infer T extends NumberLiteralEnum.One | bigint}` ? T : never; // 0n +>PExclude3 : Symbol(PExclude3, Decl(templateLiteralTypes4.ts, 210, 73)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 211, 37)) +>NumberLiteralEnum : Symbol(NumberLiteralEnum, Decl(templateLiteralTypes4.ts, 36, 90)) +>One : Symbol(NumberLiteralEnum.One, Decl(templateLiteralTypes4.ts, 38, 36)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 211, 37)) + +type PExclude4 = "100000000000000000000000" extends `${infer T extends number | bigint}` ? T : never; // 100000000000000000000000n +>PExclude4 : Symbol(PExclude4, Decl(templateLiteralTypes4.ts, 211, 93)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 212, 60)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 212, 60)) + +// infer to prefix from string +type TPrefix0 = "100" extends `${infer T extends number}${string}` ? T : never; // 1 +>TPrefix0 : Symbol(TPrefix0, Decl(templateLiteralTypes4.ts, 212, 101)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 215, 38)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 215, 38)) + +type TPrefix1 = "trueabc" extends `${infer T extends boolean}${string}` ? T : never; // boolean (T only receives 't', not the whole string) +>TPrefix1 : Symbol(TPrefix1, Decl(templateLiteralTypes4.ts, 215, 79)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 216, 42)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 216, 42)) + +type TPrefix2 = `100:${string}` extends `${infer T extends number}:${string}` ? T : never; // 100 (T receives '100' because it scans until ':') +>TPrefix2 : Symbol(TPrefix2, Decl(templateLiteralTypes4.ts, 216, 84)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 217, 48)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 217, 48)) + +// can use union w/multiple branches to extract each possibility +type ExtractPrimitives = +>ExtractPrimitives : Symbol(ExtractPrimitives, Decl(templateLiteralTypes4.ts, 217, 90)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 220, 23)) + + | T +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 220, 23)) + + | (T extends `${infer U extends number}` ? U : never) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 220, 23)) +>U : Symbol(U, Decl(templateLiteralTypes4.ts, 222, 25)) +>U : Symbol(U, Decl(templateLiteralTypes4.ts, 222, 25)) + + | (T extends `${infer U extends bigint}` ? U : never) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 220, 23)) +>U : Symbol(U, Decl(templateLiteralTypes4.ts, 223, 25)) +>U : Symbol(U, Decl(templateLiteralTypes4.ts, 223, 25)) + + | (T extends `${infer U extends boolean | null | undefined}` ? U : never) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 220, 23)) +>U : Symbol(U, Decl(templateLiteralTypes4.ts, 224, 25)) +>U : Symbol(U, Decl(templateLiteralTypes4.ts, 224, 25)) + + ; + +type TExtract0 = ExtractPrimitives<"100">; // "100" | 100 | 100n +>TExtract0 : Symbol(TExtract0, Decl(templateLiteralTypes4.ts, 225, 5)) +>ExtractPrimitives : Symbol(ExtractPrimitives, Decl(templateLiteralTypes4.ts, 217, 90)) + +type TExtract1 = ExtractPrimitives<"1.1">; // "1.1" | 1.1 +>TExtract1 : Symbol(TExtract1, Decl(templateLiteralTypes4.ts, 227, 42)) +>ExtractPrimitives : Symbol(ExtractPrimitives, Decl(templateLiteralTypes4.ts, 217, 90)) + +type TExtract2 = ExtractPrimitives<"true">; // "true" | true +>TExtract2 : Symbol(TExtract2, Decl(templateLiteralTypes4.ts, 228, 42)) +>ExtractPrimitives : Symbol(ExtractPrimitives, Decl(templateLiteralTypes4.ts, 217, 90)) + + + +// example use case (based on old TypedObjects proposal): + +// Use constrained `infer` in template literal to get ordinal indices as numbers: +type IndexFor = S extends `${infer N extends number}` ? N : never; +>IndexFor : Symbol(IndexFor, Decl(templateLiteralTypes4.ts, 229, 43)) +>S : Symbol(S, Decl(templateLiteralTypes4.ts, 236, 14)) +>S : Symbol(S, Decl(templateLiteralTypes4.ts, 236, 14)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 236, 52)) +>N : Symbol(N, Decl(templateLiteralTypes4.ts, 236, 52)) + +type IndicesOf = IndexFor>; // ordinal indices as number literals +>IndicesOf : Symbol(IndicesOf, Decl(templateLiteralTypes4.ts, 236, 84)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 237, 15)) +>IndexFor : Symbol(IndexFor, Decl(templateLiteralTypes4.ts, 229, 43)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 237, 15)) + +interface FieldDefinition { +>FieldDefinition : Symbol(FieldDefinition, Decl(templateLiteralTypes4.ts, 237, 55)) + + readonly name: string; +>name : Symbol(FieldDefinition.name, Decl(templateLiteralTypes4.ts, 239, 27)) + + readonly type: "i8" | "i16" | "i32" | "i64" | "u8" | "u16" | "u32" | "u64" | "f32" | "f64"; +>type : Symbol(FieldDefinition.type, Decl(templateLiteralTypes4.ts, 240, 26)) +} + +type FieldType = +>FieldType : Symbol(FieldType, Decl(templateLiteralTypes4.ts, 242, 1)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 244, 15)) +>FieldDefinition : Symbol(FieldDefinition, Decl(templateLiteralTypes4.ts, 237, 55)) + + T extends "i8" | "i16" | "i32" | "u8" | "u16" | "u32" | "f32" | "f64" ? number : +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 244, 15)) + + T extends "f32" | "f64" ? bigint : +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 244, 15)) + + never; + +// Generates named members like `{ x: number, y: bigint }` from `[{ name: "x", type: "i32" }, { name: "y", type: "i64" }]` +type TypedObjectNamedMembers = { +>TypedObjectNamedMembers : Symbol(TypedObjectNamedMembers, Decl(templateLiteralTypes4.ts, 247, 10)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 250, 29)) +>FieldDefinition : Symbol(FieldDefinition, Decl(templateLiteralTypes4.ts, 237, 55)) + + [P in TDef[number]["name"]]: FieldType["type"]>; +>P : Symbol(P, Decl(templateLiteralTypes4.ts, 251, 5)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 250, 29)) +>FieldType : Symbol(FieldType, Decl(templateLiteralTypes4.ts, 242, 1)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 250, 29)) +>name : Symbol(name, Decl(templateLiteralTypes4.ts, 251, 66)) +>P : Symbol(P, Decl(templateLiteralTypes4.ts, 251, 5)) + +}; + +// Generates ordinal members like `{ 0: number, 1: bigint }` from `[{ name: "x", type: "i32" }, { name: "y", type: "i64" }]` +type TypedObjectOrdinalMembers = { +>TypedObjectOrdinalMembers : Symbol(TypedObjectOrdinalMembers, Decl(templateLiteralTypes4.ts, 252, 2)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 255, 31)) +>FieldDefinition : Symbol(FieldDefinition, Decl(templateLiteralTypes4.ts, 237, 55)) + + [I in Extract]: FieldType["type"]>; +>I : Symbol(I, Decl(templateLiteralTypes4.ts, 256, 5)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 255, 31)) +>FieldType : Symbol(FieldType, Decl(templateLiteralTypes4.ts, 242, 1)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 255, 31)) +>I : Symbol(I, Decl(templateLiteralTypes4.ts, 256, 5)) +>FieldDefinition : Symbol(FieldDefinition, Decl(templateLiteralTypes4.ts, 237, 55)) + +}; + +// Default members +interface TypedObjectMembers { +>TypedObjectMembers : Symbol(TypedObjectMembers, Decl(templateLiteralTypes4.ts, 257, 2)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 260, 29)) +>FieldDefinition : Symbol(FieldDefinition, Decl(templateLiteralTypes4.ts, 237, 55)) + + // get/set a field by name + get(key: K): FieldType["type"]>; +>get : Symbol(TypedObjectMembers.get, Decl(templateLiteralTypes4.ts, 260, 71)) +>K : Symbol(K, Decl(templateLiteralTypes4.ts, 262, 8)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 260, 29)) +>key : Symbol(key, Decl(templateLiteralTypes4.ts, 262, 40)) +>K : Symbol(K, Decl(templateLiteralTypes4.ts, 262, 8)) +>FieldType : Symbol(FieldType, Decl(templateLiteralTypes4.ts, 242, 1)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 260, 29)) +>name : Symbol(name, Decl(templateLiteralTypes4.ts, 262, 82)) +>K : Symbol(K, Decl(templateLiteralTypes4.ts, 262, 8)) + + set(key: K, value: FieldType["type"]>): void; +>set : Symbol(TypedObjectMembers.set, Decl(templateLiteralTypes4.ts, 262, 112)) +>K : Symbol(K, Decl(templateLiteralTypes4.ts, 263, 8)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 260, 29)) +>key : Symbol(key, Decl(templateLiteralTypes4.ts, 263, 40)) +>K : Symbol(K, Decl(templateLiteralTypes4.ts, 263, 8)) +>value : Symbol(value, Decl(templateLiteralTypes4.ts, 263, 47)) +>FieldType : Symbol(FieldType, Decl(templateLiteralTypes4.ts, 242, 1)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 260, 29)) +>name : Symbol(name, Decl(templateLiteralTypes4.ts, 263, 88)) +>K : Symbol(K, Decl(templateLiteralTypes4.ts, 263, 8)) + + // get/set a field by index + getIndex>(index: I): FieldType["type"]>; +>getIndex : Symbol(TypedObjectMembers.getIndex, Decl(templateLiteralTypes4.ts, 263, 125)) +>I : Symbol(I, Decl(templateLiteralTypes4.ts, 266, 13)) +>IndicesOf : Symbol(IndicesOf, Decl(templateLiteralTypes4.ts, 236, 84)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 260, 29)) +>index : Symbol(index, Decl(templateLiteralTypes4.ts, 266, 40)) +>I : Symbol(I, Decl(templateLiteralTypes4.ts, 266, 13)) +>FieldType : Symbol(FieldType, Decl(templateLiteralTypes4.ts, 242, 1)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 260, 29)) +>I : Symbol(I, Decl(templateLiteralTypes4.ts, 266, 13)) +>FieldDefinition : Symbol(FieldDefinition, Decl(templateLiteralTypes4.ts, 237, 55)) + + setIndex>(index: I, value: FieldType["type"]>): void; +>setIndex : Symbol(TypedObjectMembers.setIndex, Decl(templateLiteralTypes4.ts, 266, 104)) +>I : Symbol(I, Decl(templateLiteralTypes4.ts, 267, 13)) +>IndicesOf : Symbol(IndicesOf, Decl(templateLiteralTypes4.ts, 236, 84)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 260, 29)) +>index : Symbol(index, Decl(templateLiteralTypes4.ts, 267, 40)) +>I : Symbol(I, Decl(templateLiteralTypes4.ts, 267, 13)) +>value : Symbol(value, Decl(templateLiteralTypes4.ts, 267, 49)) +>FieldType : Symbol(FieldType, Decl(templateLiteralTypes4.ts, 242, 1)) +>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 260, 29)) +>I : Symbol(I, Decl(templateLiteralTypes4.ts, 267, 13)) +>FieldDefinition : Symbol(FieldDefinition, Decl(templateLiteralTypes4.ts, 237, 55)) +} + +type TypedObject = +>TypedObject : Symbol(TypedObject, Decl(templateLiteralTypes4.ts, 268, 1)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 270, 17)) +>FieldDefinition : Symbol(FieldDefinition, Decl(templateLiteralTypes4.ts, 237, 55)) + + & TypedObjectMembers +>TypedObjectMembers : Symbol(TypedObjectMembers, Decl(templateLiteralTypes4.ts, 257, 2)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 270, 17)) + + & TypedObjectNamedMembers +>TypedObjectNamedMembers : Symbol(TypedObjectNamedMembers, Decl(templateLiteralTypes4.ts, 247, 10)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 270, 17)) + + & TypedObjectOrdinalMembers; +>TypedObjectOrdinalMembers : Symbol(TypedObjectOrdinalMembers, Decl(templateLiteralTypes4.ts, 252, 2)) +>TDef : Symbol(TDef, Decl(templateLiteralTypes4.ts, 270, 17)) + +// NOTE: type would normally be created from something like `const Point = TypedObject([...])` from which we would infer the type +type Point = TypedObject<[ +>Point : Symbol(Point, Decl(templateLiteralTypes4.ts, 273, 38)) +>TypedObject : Symbol(TypedObject, Decl(templateLiteralTypes4.ts, 268, 1)) + + { name: "x", type: "f64" }, +>name : Symbol(name, Decl(templateLiteralTypes4.ts, 277, 5)) +>type : Symbol(type, Decl(templateLiteralTypes4.ts, 277, 16)) + + { name: "y", type: "f64" }, +>name : Symbol(name, Decl(templateLiteralTypes4.ts, 278, 5)) +>type : Symbol(type, Decl(templateLiteralTypes4.ts, 278, 16)) + +]>; + +declare const p: Point; +>p : Symbol(p, Decl(templateLiteralTypes4.ts, 281, 13)) +>Point : Symbol(Point, Decl(templateLiteralTypes4.ts, 273, 38)) + +p.getIndex(0); // ok, 0 is a valid index +>p.getIndex : Symbol(TypedObjectMembers.getIndex, Decl(templateLiteralTypes4.ts, 263, 125)) +>p : Symbol(p, Decl(templateLiteralTypes4.ts, 281, 13)) +>getIndex : Symbol(TypedObjectMembers.getIndex, Decl(templateLiteralTypes4.ts, 263, 125)) + +p.getIndex(1); // ok, 1 is a valid index +>p.getIndex : Symbol(TypedObjectMembers.getIndex, Decl(templateLiteralTypes4.ts, 263, 125)) +>p : Symbol(p, Decl(templateLiteralTypes4.ts, 281, 13)) +>getIndex : Symbol(TypedObjectMembers.getIndex, Decl(templateLiteralTypes4.ts, 263, 125)) + +p.getIndex(2); // error, 2 is not a valid index +>p.getIndex : Symbol(TypedObjectMembers.getIndex, Decl(templateLiteralTypes4.ts, 263, 125)) +>p : Symbol(p, Decl(templateLiteralTypes4.ts, 281, 13)) +>getIndex : Symbol(TypedObjectMembers.getIndex, Decl(templateLiteralTypes4.ts, 263, 125)) + +p.setIndex(0, 0); // ok, 0 is a valid index +>p.setIndex : Symbol(TypedObjectMembers.setIndex, Decl(templateLiteralTypes4.ts, 266, 104)) +>p : Symbol(p, Decl(templateLiteralTypes4.ts, 281, 13)) +>setIndex : Symbol(TypedObjectMembers.setIndex, Decl(templateLiteralTypes4.ts, 266, 104)) + +p.setIndex(1, 0); // ok, 1 is a valid index +>p.setIndex : Symbol(TypedObjectMembers.setIndex, Decl(templateLiteralTypes4.ts, 266, 104)) +>p : Symbol(p, Decl(templateLiteralTypes4.ts, 281, 13)) +>setIndex : Symbol(TypedObjectMembers.setIndex, Decl(templateLiteralTypes4.ts, 266, 104)) + +p.setIndex(2, 3); // error, 2 is not a valid index +>p.setIndex : Symbol(TypedObjectMembers.setIndex, Decl(templateLiteralTypes4.ts, 266, 104)) +>p : Symbol(p, Decl(templateLiteralTypes4.ts, 281, 13)) +>setIndex : Symbol(TypedObjectMembers.setIndex, Decl(templateLiteralTypes4.ts, 266, 104)) + +// function inference +declare function f1(s: `**${T}**`): T; +>f1 : Symbol(f1, Decl(templateLiteralTypes4.ts, 288, 17)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 291, 20)) +>s : Symbol(s, Decl(templateLiteralTypes4.ts, 291, 47)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 291, 20)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 291, 20)) + +f1("**123**"); // "123" +>f1 : Symbol(f1, Decl(templateLiteralTypes4.ts, 288, 17)) + +declare function f2(s: `**${T}**`): T; +>f2 : Symbol(f2, Decl(templateLiteralTypes4.ts, 292, 14)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 294, 20)) +>s : Symbol(s, Decl(templateLiteralTypes4.ts, 294, 38)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 294, 20)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 294, 20)) + +f2("**123**"); // 123 +>f2 : Symbol(f2, Decl(templateLiteralTypes4.ts, 292, 14)) + +declare function f3(s: `**${T}**`): T; +>f3 : Symbol(f3, Decl(templateLiteralTypes4.ts, 295, 14)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 297, 20)) +>s : Symbol(s, Decl(templateLiteralTypes4.ts, 297, 38)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 297, 20)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 297, 20)) + +f3("**123**"); // 123n +>f3 : Symbol(f3, Decl(templateLiteralTypes4.ts, 295, 14)) + +declare function f4(s: `**${T}**`): T; +>f4 : Symbol(f4, Decl(templateLiteralTypes4.ts, 298, 14)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 300, 20)) +>s : Symbol(s, Decl(templateLiteralTypes4.ts, 300, 39)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 300, 20)) +>T : Symbol(T, Decl(templateLiteralTypes4.ts, 300, 20)) + +f4("**true**"); // true | "true" +>f4 : Symbol(f4, Decl(templateLiteralTypes4.ts, 298, 14)) + +f4("**false**"); // false | "false" +>f4 : Symbol(f4, Decl(templateLiteralTypes4.ts, 298, 14)) + diff --git a/tests/baselines/reference/templateLiteralTypes4.types b/tests/baselines/reference/templateLiteralTypes4.types new file mode 100644 index 00000000000..d9a1064bec0 --- /dev/null +++ b/tests/baselines/reference/templateLiteralTypes4.types @@ -0,0 +1,608 @@ +=== tests/cases/conformance/types/literal/templateLiteralTypes4.ts === +// infer from number +type TNumber0 = "100" extends `${infer N extends number}` ? N : never; // 100 +>TNumber0 : 100 + +type TNumber1 = "-100" extends `${infer N extends number}` ? N : never; // -100 +>TNumber1 : -100 + +type TNumber2 = "1.1" extends `${infer N extends number}` ? N : never; // 1.1 +>TNumber2 : 1.1 + +type TNumber3 = "8e-11" extends `${infer N extends number}` ? N : never; // 8e-11 (0.00000000008) +>TNumber3 : 8e-11 + +type TNumber4 = "0x10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +>TNumber4 : number + +type TNumber5 = "0o10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +>TNumber5 : number + +type TNumber6 = "0b10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +>TNumber6 : number + +type TNumber7 = "10e2" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +>TNumber7 : number + +type TNumber8 = "abcd" extends `${infer N extends number}` ? N : never; // never +>TNumber8 : never + +// infer from bigint +type TBigInt0 = "100" extends `${infer N extends bigint}` ? N : never; // 100n +>TBigInt0 : 100n + +type TBigInt1 = "-100" extends `${infer N extends bigint}` ? N : never; // -100n +>TBigInt1 : -100n + +type TBigInt2 = "0x10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) +>TBigInt2 : bigint + +type TBigInt3 = "0o10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) +>TBigInt3 : bigint + +type TBigInt4 = "0b10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) +>TBigInt4 : bigint + +type TBigInt5 = "1.1" extends `${infer N extends bigint}` ? N : never; // never +>TBigInt5 : never + +type TBigInt6 = "10e2" extends `${infer N extends bigint}` ? N : never; // never +>TBigInt6 : never + +type TBigInt7 = "abcd" extends `${infer N extends bigint}` ? N : never; // never +>TBigInt7 : never + +// infer from boolean +type TBoolean0 = "true" extends `${infer T extends boolean}` ? T : never; // true +>TBoolean0 : true + +type TBoolean1 = "false" extends `${infer T extends boolean}` ? T : never; // false +>TBoolean1 : false + +type TBoolean2 = "abcd" extends `${infer T extends boolean}` ? T : never; // never +>TBoolean2 : never + +// infer from null +type TNull0 = "null" extends `${infer T extends null}` ? T : never; // null +>TNull0 : null +>null : null + +type TNull1 = "abcd" extends `${infer T extends null}` ? T : never; // never +>TNull1 : never +>null : null + +// infer from undefined +type TUndefined0 = "undefined" extends `${infer T extends undefined}` ? T : never; // undefined +>TUndefined0 : undefined + +type TUndefined1 = "abcd" extends `${infer T extends undefined}` ? T : never; // never +>TUndefined1 : never + +// infer from literal enums +const enum StringLiteralEnum { Zero = "0", True = "true", False = "false", Undefined = "undefined", Null = "null" } +>StringLiteralEnum : StringLiteralEnum +>Zero : StringLiteralEnum.Zero +>"0" : "0" +>True : StringLiteralEnum.True +>"true" : "true" +>False : StringLiteralEnum.False +>"false" : "false" +>Undefined : StringLiteralEnum.Undefined +>"undefined" : "undefined" +>Null : StringLiteralEnum.Null +>"null" : "null" + +type TStringLiteralEnum0 = "0" extends `${infer T extends StringLiteralEnum}` ? T : never; // StringLiteralEnum.Zero +>TStringLiteralEnum0 : StringLiteralEnum.Zero + +const enum NumberLiteralEnum { Zero, One } +>NumberLiteralEnum : NumberLiteralEnum +>Zero : NumberLiteralEnum.Zero +>One : NumberLiteralEnum.One + +type TNumberLiteralEnum0 = "0" extends `${infer T extends NumberLiteralEnum}` ? T : never; // NumberLiteralEnum.Zero +>TNumberLiteralEnum0 : NumberLiteralEnum.Zero + +// infer from non-literal enums +const enum NonLiteralEnum { Zero = NumberLiteralEnum.Zero, One = NumberLiteralEnum.One } +>NonLiteralEnum : NonLiteralEnum +>Zero : NonLiteralEnum +>NumberLiteralEnum.Zero : NumberLiteralEnum.Zero +>NumberLiteralEnum : typeof NumberLiteralEnum +>Zero : NumberLiteralEnum.Zero +>One : NonLiteralEnum +>NumberLiteralEnum.One : NumberLiteralEnum.One +>NumberLiteralEnum : typeof NumberLiteralEnum +>One : NumberLiteralEnum.One + +type TNonLiteralEnum0 = "0" extends `${infer T extends NonLiteralEnum}` ? T : never; // 0 +>TNonLiteralEnum0 : 0 + +// infer using priority: +// string > template-literal > (string-literal | string-literal-enum) > +// number > enum > (number-literal | number-literal-enum) > +// bigint > bigint-literal > +// boolean > (boolean-literal | undefined | null) + +// #region string +// string > string-literal-enum +type PString00 = "0" extends `${infer T extends string | StringLiteralEnum}` ? T : never; // "0" +>PString00 : "0" + +// string > number +type PString01 = "0" extends `${infer T extends string | number}` ? T : never; // "0" +>PString01 : "0" + +// string > enum +type PString02 = "0" extends `${infer T extends string | NonLiteralEnum}` ? T : never; // "0" +>PString02 : "0" + +// string > (number-literal | number-literal-enum) +type PString03 = "0" extends `${infer T extends string | 0}` ? T : never; // "0" +>PString03 : "0" + +type PString04 = "0" extends `${infer T extends string | NumberLiteralEnum}` ? T : never; // "0" +>PString04 : "0" + +// string > bigint +type PString05 = "0" extends `${infer T extends string | bigint}` ? T : never; // "0" +>PString05 : "0" + +// string > bigint-literal +type PString06 = "0" extends `${infer T extends string | 0n}` ? T : never; // "0" +>PString06 : "0" + +// string > boolean +type PString07 = "true" extends `${infer T extends string | boolean}` ? T : never; // "true" +>PString07 : "true" + +type PString08 = "false" extends `${infer T extends string | boolean}` ? T : never; // "false" +>PString08 : "false" + +// string > (boolean-literal | undefined | null) +type PString09 = "true" extends `${infer T extends string | true}` ? T : never; // "true" +>PString09 : "true" +>true : true + +type PString10 = "false" extends `${infer T extends string | false}` ? T : never; // "false" +>PString10 : "false" +>false : false + +type PString11 = "undefined" extends `${infer T extends string | undefined}` ? T : never; // "undefined" +>PString11 : "undefined" + +type PString12 = "null" extends `${infer T extends string | null}` ? T : never; // "null" +>PString12 : "null" +>null : null + +// #endregion string + +// #region template-literal +// template-literal > number +type PTemplate00 = "10" extends `${infer T extends `1${string}` | number}` ? T : never; // "10" +>PTemplate00 : "10" + +// template-literal > enum +type PTemplate01 = "10" extends `${infer T extends `1${string}` | NonLiteralEnum}` ? T : never; // "10" +>PTemplate01 : "10" + +// template-literal > (number-literal | number-literal-enum) +type PTemplate02 = "10" extends `${infer T extends `1${string}` | 10}` ? T : never; // "10" +>PTemplate02 : "10" + +type PTemplate03 = "10" extends `${infer T extends `1${string}` | NumberLiteralEnum}` ? T : never; // "10" +>PTemplate03 : "10" + +// template-literal > bigint +type PTemplate04 = "10" extends `${infer T extends `1${string}` | bigint}` ? T : never; // "10" +>PTemplate04 : "10" + +// template-literal > bigint-literal +type PTemplate05 = "10" extends `${infer T extends `1${string}` | 10n}` ? T : never; // "10" +>PTemplate05 : "10" + +// template-literal > boolean +type PTemplate06 = "true" extends `${infer T extends `${string}e` | boolean}` ? T : never; // "true" +>PTemplate06 : "true" + +type PTemplate07 = "false" extends `${infer T extends `${string}e` | boolean}` ? T : never; // "false" +>PTemplate07 : "false" + +// template-literal > (boolean-literal | undefined | null) +type PTemplate08 = "true" extends `${infer T extends `${"t"}${string}` | true}` ? T : never; // "true" +>PTemplate08 : "true" +>true : true + +type PTemplate09 = "false" extends `${infer T extends `${"f"}${string}` | false}` ? T : never; // "false" +>PTemplate09 : "false" +>false : false + +type PTemplate10 = "undefined" extends `${infer T extends `${"u"}${string}` | undefined}` ? T : never; // "undefined" +>PTemplate10 : "undefined" + +type PTemplate11 = "null" extends `${infer T extends `${"n"}${string}` | null}` ? T : never; // "null" +>PTemplate11 : "null" +>null : null + +// #endregion template-literal + +// #region string-literal +// string-literal > number +type PStringLiteral00 = "0" extends `${infer T extends "0" | number}` ? T : never; // "0" +>PStringLiteral00 : "0" + +// string-literal > enum +type PStringLiteral01 = "0" extends `${infer T extends "0" | NonLiteralEnum}` ? T : never; // "0" +>PStringLiteral01 : "0" + +// string-literal > (number-literal | number-literal-enum) +type PStringLiteral02 = "0" extends `${infer T extends "0" | 0}` ? T : never; // "0" +>PStringLiteral02 : "0" + +type PStringLiteral03 = "0" extends `${infer T extends "0" | NumberLiteralEnum}` ? T : never; // "0" +>PStringLiteral03 : "0" + +// string-literal > bigint +type PStringLiteral04 = "0" extends `${infer T extends "0" | bigint}` ? T : never; // "0" +>PStringLiteral04 : "0" + +// string-literal > bigint-literal +type PStringLiteral05 = "0" extends `${infer T extends "0" | 0n}` ? T : never; // "0" +>PStringLiteral05 : "0" + +// string-literal > boolean +type PStringLiteral06 = "true" extends `${infer T extends "true" | "false" | boolean}` ? T : never; // "true" +>PStringLiteral06 : "true" + +type PStringLiteral07 = "false" extends `${infer T extends "true" | "false" | boolean}` ? T : never; // "false" +>PStringLiteral07 : "false" + +// string-literal > (boolean-literal | undefined | null) +type PStringLiteral08 = "true" extends `${infer T extends "true" | true}` ? T : never; // "true" +>PStringLiteral08 : "true" +>true : true + +type PStringLiteral09 = "false" extends `${infer T extends "false" | false}` ? T : never; // "false" +>PStringLiteral09 : "false" +>false : false + +type PStringLiteral10 = "undefined" extends `${infer T extends "undefined" | undefined}` ? T : never; // "undefined" +>PStringLiteral10 : "undefined" + +type PStringLiteral11 = "null" extends `${infer T extends "null" | null}` ? T : never; // "null" +>PStringLiteral11 : "null" +>null : null + +// #endregion string-literal + +// #region string-literal-enum +// string-literal-enum > number +type PStringLiteralEnum00 = "0" extends `${infer T extends StringLiteralEnum | number}` ? T : never; // StringLiteralEnum.Zero +>PStringLiteralEnum00 : StringLiteralEnum.Zero + +// string-literal-enum > enum +type PStringLiteralEnum01 = "0" extends `${infer T extends StringLiteralEnum | NonLiteralEnum}` ? T : never; // StringLiteralEnum.Zero +>PStringLiteralEnum01 : StringLiteralEnum.Zero + +// string-literal-enum > (number-literal | number-literal-enum) +type PStringLiteralEnum02 = "0" extends `${infer T extends StringLiteralEnum | 0}` ? T : never; // StringLiteralEnum.Zero +>PStringLiteralEnum02 : StringLiteralEnum.Zero + +type PStringLiteralEnum03 = "0" extends `${infer T extends StringLiteralEnum | NumberLiteralEnum}` ? T : never; // StringLiteralEnum.Zero +>PStringLiteralEnum03 : StringLiteralEnum.Zero + +// string-literal-enum > bigint +type PStringLiteralEnum04 = "0" extends `${infer T extends StringLiteralEnum | bigint}` ? T : never; // StringLiteralEnum.Zero +>PStringLiteralEnum04 : StringLiteralEnum.Zero + +// string-literal-enum > bigint-literal +type PStringLiteralEnum05 = "0" extends `${infer T extends StringLiteralEnum | 0n}` ? T : never; // StringLiteralEnum.Zero +>PStringLiteralEnum05 : StringLiteralEnum.Zero + +// string-literal-enum > boolean +type PStringLiteralEnum06 = "true" extends `${infer T extends StringLiteralEnum | boolean}` ? T : never; // StringLiteralEnum.True +>PStringLiteralEnum06 : StringLiteralEnum.True + +type PStringLiteralEnum07 = "false" extends `${infer T extends StringLiteralEnum | boolean}` ? T : never; // StringLiteralEnum.False +>PStringLiteralEnum07 : StringLiteralEnum.False + +// string-literal-enum > (boolean-literal | undefined | null) +type PStringLiteralEnum08 = "true" extends `${infer T extends StringLiteralEnum | true}` ? T : never; // StringLiteralEnum.True +>PStringLiteralEnum08 : StringLiteralEnum.True +>true : true + +type PStringLiteralEnum09 = "false" extends `${infer T extends StringLiteralEnum | false}` ? T : never; // StringLiteralEnum.False +>PStringLiteralEnum09 : StringLiteralEnum.False +>false : false + +type PStringLiteralEnum10 = "undefined" extends `${infer T extends StringLiteralEnum | undefined}` ? T : never; // StringLiteralEnum.Undefined +>PStringLiteralEnum10 : StringLiteralEnum.Undefined + +type PStringLiteralEnum11 = "null" extends `${infer T extends StringLiteralEnum | null}` ? T : never; // StringLiteralEnum.Null +>PStringLiteralEnum11 : StringLiteralEnum.Null +>null : null + +// #endregion string-literal-enum + +// #region number +// number > enum +type PNumber0 = "0" extends `${infer T extends number | NonLiteralEnum}` ? T : never; // 0 +>PNumber0 : 0 + +// number > number-literal-enum +type PNumber1 = "0" extends `${infer T extends number | NumberLiteralEnum}` ? T : never; // 0 +>PNumber1 : 0 + +// number > bigint +type PNumber2 = "0" extends `${infer T extends number | bigint}` ? T : never; // 0 +>PNumber2 : 0 + +// number > bigint-literal +type PNumber3 = "0" extends `${infer T extends number | 0n}` ? T : never; // 0 +>PNumber3 : 0 + +// #endregion number + +// #region enum +// enum > number-literal-enum +type PEnum0 = "0" extends `${infer T extends NonLiteralEnum | NumberLiteralEnum}` ? T : never; // 0 +>PEnum0 : 0 + +// enum > bigint +type PEnum1 = "0" extends `${infer T extends NonLiteralEnum | bigint}` ? T : never; // 0 +>PEnum1 : 0 + +// enum > bigint-literal +type PEnum2 = "0" extends `${infer T extends NonLiteralEnum | 0n}` ? T : never; // 0 +>PEnum2 : 0 + +// #endregion enum + +// #region number-literal +// number-literal > bigint +type PNumberLiteral0 = "0" extends `${infer T extends 0 | bigint}` ? T : never; // 0 +>PNumberLiteral0 : 0 + +// number-literal > bigint-literal +type PNumberLiteral1 = "0" extends `${infer T extends 0 | 0n}` ? T : never; // 0 +>PNumberLiteral1 : 0 + +// #endregion number-literal + +// #region number-literal-enum +// number-literal-enum > bigint +type PNumberLiteralEnum0 = "0" extends `${infer T extends NumberLiteralEnum | bigint}` ? T : never; // NumberLiteralEnum.Zero +>PNumberLiteralEnum0 : NumberLiteralEnum.Zero + +// number-literal-enum > bigint-literal +type PNumberLiteralEnum1 = "0" extends `${infer T extends NumberLiteralEnum | 0n}` ? T : never; // NumberLiteralEnum.Zero +>PNumberLiteralEnum1 : NumberLiteralEnum.Zero + +// #endregion number-literal-enum + +// non-matchable constituents are excluded +type PExclude0 = "0" extends `${infer T extends "1" | number}` ? T : never; // 0 +>PExclude0 : 0 + +type PExclude1 = "0" extends `${infer T extends `1${string}` | number}` ? T : never; // 0 +>PExclude1 : 0 + +type PExclude2 = "0" extends `${infer T extends 1 | bigint}` ? T : never; // 0n +>PExclude2 : 0n + +type PExclude3 = "0" extends `${infer T extends NumberLiteralEnum.One | bigint}` ? T : never; // 0n +>PExclude3 : 0n +>NumberLiteralEnum : any + +type PExclude4 = "100000000000000000000000" extends `${infer T extends number | bigint}` ? T : never; // 100000000000000000000000n +>PExclude4 : 100000000000000000000000n + +// infer to prefix from string +type TPrefix0 = "100" extends `${infer T extends number}${string}` ? T : never; // 1 +>TPrefix0 : 1 + +type TPrefix1 = "trueabc" extends `${infer T extends boolean}${string}` ? T : never; // boolean (T only receives 't', not the whole string) +>TPrefix1 : boolean + +type TPrefix2 = `100:${string}` extends `${infer T extends number}:${string}` ? T : never; // 100 (T receives '100' because it scans until ':') +>TPrefix2 : 100 + +// can use union w/multiple branches to extract each possibility +type ExtractPrimitives = +>ExtractPrimitives : ExtractPrimitives + + | T + | (T extends `${infer U extends number}` ? U : never) + | (T extends `${infer U extends bigint}` ? U : never) + | (T extends `${infer U extends boolean | null | undefined}` ? U : never) +>null : null + + ; + +type TExtract0 = ExtractPrimitives<"100">; // "100" | 100 | 100n +>TExtract0 : "100" | 100 | 100n + +type TExtract1 = ExtractPrimitives<"1.1">; // "1.1" | 1.1 +>TExtract1 : "1.1" | 1.1 + +type TExtract2 = ExtractPrimitives<"true">; // "true" | true +>TExtract2 : true | "true" + + + +// example use case (based on old TypedObjects proposal): + +// Use constrained `infer` in template literal to get ordinal indices as numbers: +type IndexFor = S extends `${infer N extends number}` ? N : never; +>IndexFor : IndexFor + +type IndicesOf = IndexFor>; // ordinal indices as number literals +>IndicesOf : IndicesOf + +interface FieldDefinition { + readonly name: string; +>name : string + + readonly type: "i8" | "i16" | "i32" | "i64" | "u8" | "u16" | "u32" | "u64" | "f32" | "f64"; +>type : "i8" | "i16" | "i32" | "i64" | "u8" | "u16" | "u32" | "u64" | "f32" | "f64" +} + +type FieldType = +>FieldType : FieldType + + T extends "i8" | "i16" | "i32" | "u8" | "u16" | "u32" | "f32" | "f64" ? number : + T extends "f32" | "f64" ? bigint : + never; + +// Generates named members like `{ x: number, y: bigint }` from `[{ name: "x", type: "i32" }, { name: "y", type: "i64" }]` +type TypedObjectNamedMembers = { +>TypedObjectNamedMembers : TypedObjectNamedMembers + + [P in TDef[number]["name"]]: FieldType["type"]>; +>name : P + +}; + +// Generates ordinal members like `{ 0: number, 1: bigint }` from `[{ name: "x", type: "i32" }, { name: "y", type: "i64" }]` +type TypedObjectOrdinalMembers = { +>TypedObjectOrdinalMembers : TypedObjectOrdinalMembers + + [I in Extract]: FieldType["type"]>; +}; + +// Default members +interface TypedObjectMembers { + // get/set a field by name + get(key: K): FieldType["type"]>; +>get : (key: K) => FieldType["type"]> +>key : K +>name : K + + set(key: K, value: FieldType["type"]>): void; +>set : (key: K, value: FieldType["type"]>) => void +>key : K +>value : FieldType["type"]> +>name : K + + // get/set a field by index + getIndex>(index: I): FieldType["type"]>; +>getIndex : >>(index: I) => FieldType["type"]> +>index : I + + setIndex>(index: I, value: FieldType["type"]>): void; +>setIndex : >>(index: I, value: FieldType["type"]>) => void +>index : I +>value : FieldType["type"]> +} + +type TypedObject = +>TypedObject : TypedObject + + & TypedObjectMembers + & TypedObjectNamedMembers + & TypedObjectOrdinalMembers; + +// NOTE: type would normally be created from something like `const Point = TypedObject([...])` from which we would infer the type +type Point = TypedObject<[ +>Point : TypedObjectMembers<[{ name: "x"; type: "f64"; }, { name: "y"; type: "f64"; }]> & TypedObjectNamedMembers<[{ name: "x"; type: "f64"; }, { name: "y"; type: "f64"; }]> & TypedObjectOrdinalMembers<[{ name: "x"; type: "f64"; }, { name: "y"; type: "f64"; }]> + + { name: "x", type: "f64" }, +>name : "x" +>type : "f64" + + { name: "y", type: "f64" }, +>name : "y" +>type : "f64" + +]>; + +declare const p: Point; +>p : Point + +p.getIndex(0); // ok, 0 is a valid index +>p.getIndex(0) : number +>p.getIndex : (index: I) => FieldType["type"]> +>p : Point +>getIndex : (index: I) => FieldType["type"]> +>0 : 0 + +p.getIndex(1); // ok, 1 is a valid index +>p.getIndex(1) : number +>p.getIndex : (index: I) => FieldType["type"]> +>p : Point +>getIndex : (index: I) => FieldType["type"]> +>1 : 1 + +p.getIndex(2); // error, 2 is not a valid index +>p.getIndex(2) : number +>p.getIndex : (index: I) => FieldType["type"]> +>p : Point +>getIndex : (index: I) => FieldType["type"]> +>2 : 2 + +p.setIndex(0, 0); // ok, 0 is a valid index +>p.setIndex(0, 0) : void +>p.setIndex : (index: I, value: FieldType["type"]>) => void +>p : Point +>setIndex : (index: I, value: FieldType["type"]>) => void +>0 : 0 +>0 : 0 + +p.setIndex(1, 0); // ok, 1 is a valid index +>p.setIndex(1, 0) : void +>p.setIndex : (index: I, value: FieldType["type"]>) => void +>p : Point +>setIndex : (index: I, value: FieldType["type"]>) => void +>1 : 1 +>0 : 0 + +p.setIndex(2, 3); // error, 2 is not a valid index +>p.setIndex(2, 3) : void +>p.setIndex : (index: I, value: FieldType["type"]>) => void +>p : Point +>setIndex : (index: I, value: FieldType["type"]>) => void +>2 : 2 +>3 : 3 + +// function inference +declare function f1(s: `**${T}**`): T; +>f1 : (s: `**${T}**`) => T +>s : `**${T}**` + +f1("**123**"); // "123" +>f1("**123**") : "123" +>f1 : (s: `**${T}**`) => T +>"**123**" : "**123**" + +declare function f2(s: `**${T}**`): T; +>f2 : (s: `**${T}**`) => T +>s : `**${T}**` + +f2("**123**"); // 123 +>f2("**123**") : 123 +>f2 : (s: `**${T}**`) => T +>"**123**" : "**123**" + +declare function f3(s: `**${T}**`): T; +>f3 : (s: `**${T}**`) => T +>s : `**${T}**` + +f3("**123**"); // 123n +>f3("**123**") : 123n +>f3 : (s: `**${T}**`) => T +>"**123**" : "**123**" + +declare function f4(s: `**${T}**`): T; +>f4 : (s: `**${T}**`) => T +>s : `**${T}**` + +f4("**true**"); // true | "true" +>f4("**true**") : true +>f4 : (s: `**${T}**`) => T +>"**true**" : "**true**" + +f4("**false**"); // false | "false" +>f4("**false**") : false +>f4 : (s: `**${T}**`) => T +>"**false**" : "**false**" + diff --git a/tests/baselines/reference/tsxNotUsingApparentTypeOfSFC.errors.txt b/tests/baselines/reference/tsxNotUsingApparentTypeOfSFC.errors.txt index 81231a34562..a967c92e555 100644 --- a/tests/baselines/reference/tsxNotUsingApparentTypeOfSFC.errors.txt +++ b/tests/baselines/reference/tsxNotUsingApparentTypeOfSFC.errors.txt @@ -5,9 +5,17 @@ tests/cases/compiler/tsxNotUsingApparentTypeOfSFC.tsx(15,14): error TS2769: No o Type '{}' is not assignable to type 'Readonly

'. Overload 2 of 2, '(props: P, context?: any): MyComponent', gave the following error. Type '{}' is not assignable to type 'Readonly

'. +tests/cases/compiler/tsxNotUsingApparentTypeOfSFC.tsx(17,14): error TS2322: Type 'P' is not assignable to type 'IntrinsicAttributes & P'. + Type 'P' is not assignable to type 'IntrinsicAttributes'. +tests/cases/compiler/tsxNotUsingApparentTypeOfSFC.tsx(18,14): error TS2769: No overload matches this call. + Overload 1 of 2, '(props: Readonly

): MyComponent', gave the following error. + Type 'P' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly

'. + Type 'P' is not assignable to type 'IntrinsicAttributes'. + Overload 2 of 2, '(props: P, context?: any): MyComponent', gave the following error. + Type 'P' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly

'. -==== tests/cases/compiler/tsxNotUsingApparentTypeOfSFC.tsx (2 errors) ==== +==== tests/cases/compiler/tsxNotUsingApparentTypeOfSFC.tsx (4 errors) ==== /// import React from 'react'; @@ -34,5 +42,17 @@ tests/cases/compiler/tsxNotUsingApparentTypeOfSFC.tsx(15,14): error TS2769: No o !!! error TS2769: Type '{}' is not assignable to type 'Readonly

'. let z = // should work + ~~~~~ +!!! error TS2322: Type 'P' is not assignable to type 'IntrinsicAttributes & P'. +!!! error TS2322: Type 'P' is not assignable to type 'IntrinsicAttributes'. +!!! related TS2208 tests/cases/compiler/tsxNotUsingApparentTypeOfSFC.tsx:5:15: This type parameter probably needs an `extends object` constraint. let q = // should work + ~~~~~~~~~~~ +!!! error TS2769: No overload matches this call. +!!! error TS2769: Overload 1 of 2, '(props: Readonly

): MyComponent', gave the following error. +!!! error TS2769: Type 'P' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly

'. +!!! error TS2769: Type 'P' is not assignable to type 'IntrinsicAttributes'. +!!! error TS2769: Overload 2 of 2, '(props: P, context?: any): MyComponent', gave the following error. +!!! error TS2769: Type 'P' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{ children?: ReactNode; }> & Readonly

'. +!!! related TS2208 tests/cases/compiler/tsxNotUsingApparentTypeOfSFC.tsx:5:15: This type parameter probably needs an `extends object` constraint. } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardTypeOfUndefined.types b/tests/baselines/reference/typeGuardTypeOfUndefined.types index 79f87e101ca..ffc82e57e66 100644 --- a/tests/baselines/reference/typeGuardTypeOfUndefined.types +++ b/tests/baselines/reference/typeGuardTypeOfUndefined.types @@ -242,7 +242,7 @@ function test9(a: boolean | number) { } else { a; ->a : undefined +>a : never } } @@ -259,7 +259,7 @@ function test10(a: boolean | number) { if (typeof a === "boolean") { >typeof a === "boolean" : boolean >typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->a : undefined +>a : never >"boolean" : "boolean" a; @@ -267,7 +267,7 @@ function test10(a: boolean | number) { } else { a; ->a : undefined +>a : never } } else { diff --git a/tests/baselines/reference/typeVariableTypeGuards.types b/tests/baselines/reference/typeVariableTypeGuards.types index 9f6f45935a7..2274589cb8c 100644 --- a/tests/baselines/reference/typeVariableTypeGuards.types +++ b/tests/baselines/reference/typeVariableTypeGuards.types @@ -193,8 +193,8 @@ function f5(obj: T | undefined, key: K) { >obj : T | undefined obj[key]; ->obj[key] : T[K] ->obj : T +>obj[key] : NonNullable[K] +>obj : NonNullable >key : K } } diff --git a/tests/baselines/reference/unionWithIndexSignature.types b/tests/baselines/reference/unionWithIndexSignature.types index 5acb5391f81..7aa5877e37a 100644 --- a/tests/baselines/reference/unionWithIndexSignature.types +++ b/tests/baselines/reference/unionWithIndexSignature.types @@ -21,7 +21,7 @@ export function foo(arr: T & (NumList | StrList)) { let zz = arr[1]; // Error >zz : string | number >arr[1] : string | number ->arr : T & (NumList | StrList) +>arr : NumList | StrList >1 : 1 } diff --git a/tests/baselines/reference/unknownControlFlow.errors.txt b/tests/baselines/reference/unknownControlFlow.errors.txt new file mode 100644 index 00000000000..540c0134e2d --- /dev/null +++ b/tests/baselines/reference/unknownControlFlow.errors.txt @@ -0,0 +1,266 @@ +tests/cases/conformance/types/unknown/unknownControlFlow.ts(18,9): error TS2322: Type 'unknown' is not assignable to type '{}'. + + +==== tests/cases/conformance/types/unknown/unknownControlFlow.ts (1 errors) ==== + type T01 = {} & string; // string + type T02 = {} & 'a'; // 'a' + type T03 = {} & object; // object + type T04 = {} & { x: number }; // { x: number } + type T05 = {} & null; // never + type T06 = {} & undefined; // never + type T07 = undefined & void; // undefined + + type T10 = string & {}; // Specially preserved + type T11 = number & {}; // Specially preserved + type T12 = bigint & {}; // Specially preserved + + type ThisNode = {}; + type ThatNode = {}; + type ThisOrThatNode = ThisNode | ThatNode; + + function f01(u: unknown) { + let x1: {} = u; // Error + ~~ +!!! error TS2322: Type 'unknown' is not assignable to type '{}'. + let x2: {} | null | undefined = u; + let x3: {} | { x: string } | null | undefined = u; + let x4: ThisOrThatNode | null | undefined = u; + } + + function f10(x: unknown) { + if (x) { + x; // {} + } + else { + x; // unknown + } + if (!x) { + x; // unknown + } + else { + x; // {} + } + } + + function f11(x: T) { + if (x) { + x; // T & {} + } + else { + x; // T + } + if (!x) { + x; // T + } + else { + x; // T & {} + } + } + + function f12(x: T) { + if (x) { + x; // T + } + else { + x; // T + } + } + + function f20(x: unknown) { + if (x !== undefined) { + x; // {} | null + } + else { + x; // undefined + } + if (x !== null) { + x; // {} | undefined + } + else { + x; // null + } + if (x !== undefined && x !== null) { + x; // {} + } + else { + x; // null | undefined + } + if (x != undefined) { + x; // {} + } + else { + x; // null | undefined + } + if (x != null) { + x; // {} + } + else { + x; // null | undefined + } + } + + function f21(x: T) { + if (x !== undefined) { + x; // T & ({} | null) + } + else { + x; // T + } + if (x !== null) { + x; // T & ({} | undefined) + } + else { + x; // T + } + if (x !== undefined && x !== null) { + x; // T & {} + } + else { + x; // T + } + if (x != undefined) { + x; // T & {} + } + else { + x; // T + } + if (x != null) { + x; // T & {} + } + else { + x; // T + } + } + + function f22(x: T) { + if (x !== undefined) { + x; // T & {} + } + else { + x; // T + } + if (x !== null) { + x; // T + } + else { + x; // T + } + if (x !== undefined && x !== null) { + x; // T & {} + } + else { + x; // T + } + if (x != undefined) { + x; // T & {} + } + else { + x; // T + } + if (x != null) { + x; // T & {} + } + else { + x; // T + } + } + + function f23(x: T | undefined | null) { + if (x !== undefined) { + x; // T & {} | null + } + if (x !== null) { + x; // T & {} | undefined + } + if (x != undefined) { + x; // T & {} + } + if (x != null) { + x; // T & {} + } + } + + function f30(x: {}) { + if (typeof x === "object") { + x; // object + } + } + + function f31(x: T) { + if (typeof x === "object") { + x; // T & object | T & null + } + if (x && typeof x === "object") { + x; // T & object + } + if (typeof x === "object" && x) { + x; // T & object + } + } + + function f32(x: T) { + if (typeof x === "object") { + x; // T & object + } + } + + function possiblyNull(x: T) { + return !!true ? x : null; // T | null + } + + function possiblyUndefined(x: T) { + return !!true ? x : undefined; // T | undefined + } + + function possiblyNullOrUndefined(x: T) { + return possiblyUndefined(possiblyNull(x)); // T | null | undefined + } + + function ensureNotNull(x: T) { + if (x === null) throw Error(); + return x; // T & ({} | undefined) + } + + function ensureNotUndefined(x: T) { + if (x === undefined) throw Error(); + return x; // T & ({} | null) + } + + function ensureNotNullOrUndefined(x: T) { + return ensureNotUndefined(ensureNotNull(x)); // T & {} + } + + function f40(a: string | undefined, b: number | null | undefined) { + let a1 = ensureNotNullOrUndefined(a); // string + let b1 = ensureNotNullOrUndefined(b); // number + } + + type QQ = NonNullable>>; + + function f41(a: T) { + let a1 = ensureNotUndefined(ensureNotNull(a)); // T & {} + let a2 = ensureNotNull(ensureNotUndefined(a)); // T & {} + let a3 = ensureNotNull(ensureNotNull(a)); // T & {} | T & undefined + let a4 = ensureNotUndefined(ensureNotUndefined(a)); // T & {} | T & null + let a5 = ensureNotNullOrUndefined(ensureNotNullOrUndefined(a)); // T & {} + let a6 = ensureNotNull(possiblyNullOrUndefined(a)); // T & {} | undefined + let a7 = ensureNotUndefined(possiblyNullOrUndefined(a)); // T & {} | null + let a8 = ensureNotNull(possiblyUndefined(a)); // T & {} | undefined + let a9 = ensureNotUndefined(possiblyNull(a)); // T & {} | null + } + + // Repro from #48468 + + function deepEquals(a: T, b: T): boolean { + if (typeof a !== 'object' || typeof b !== 'object' || !a || !b) { + return false; + } + if (Array.isArray(a) || Array.isArray(b)) { + return false; + } + if (Object.keys(a).length !== Object.keys(b).length) { // Error here + return false; + } + return true; + } + \ No newline at end of file diff --git a/tests/baselines/reference/unknownControlFlow.js b/tests/baselines/reference/unknownControlFlow.js new file mode 100644 index 00000000000..0cc3d1d0d77 --- /dev/null +++ b/tests/baselines/reference/unknownControlFlow.js @@ -0,0 +1,526 @@ +//// [unknownControlFlow.ts] +type T01 = {} & string; // string +type T02 = {} & 'a'; // 'a' +type T03 = {} & object; // object +type T04 = {} & { x: number }; // { x: number } +type T05 = {} & null; // never +type T06 = {} & undefined; // never +type T07 = undefined & void; // undefined + +type T10 = string & {}; // Specially preserved +type T11 = number & {}; // Specially preserved +type T12 = bigint & {}; // Specially preserved + +type ThisNode = {}; +type ThatNode = {}; +type ThisOrThatNode = ThisNode | ThatNode; + +function f01(u: unknown) { + let x1: {} = u; // Error + let x2: {} | null | undefined = u; + let x3: {} | { x: string } | null | undefined = u; + let x4: ThisOrThatNode | null | undefined = u; +} + +function f10(x: unknown) { + if (x) { + x; // {} + } + else { + x; // unknown + } + if (!x) { + x; // unknown + } + else { + x; // {} + } +} + +function f11(x: T) { + if (x) { + x; // T & {} + } + else { + x; // T + } + if (!x) { + x; // T + } + else { + x; // T & {} + } +} + +function f12(x: T) { + if (x) { + x; // T + } + else { + x; // T + } +} + +function f20(x: unknown) { + if (x !== undefined) { + x; // {} | null + } + else { + x; // undefined + } + if (x !== null) { + x; // {} | undefined + } + else { + x; // null + } + if (x !== undefined && x !== null) { + x; // {} + } + else { + x; // null | undefined + } + if (x != undefined) { + x; // {} + } + else { + x; // null | undefined + } + if (x != null) { + x; // {} + } + else { + x; // null | undefined + } +} + +function f21(x: T) { + if (x !== undefined) { + x; // T & ({} | null) + } + else { + x; // T + } + if (x !== null) { + x; // T & ({} | undefined) + } + else { + x; // T + } + if (x !== undefined && x !== null) { + x; // T & {} + } + else { + x; // T + } + if (x != undefined) { + x; // T & {} + } + else { + x; // T + } + if (x != null) { + x; // T & {} + } + else { + x; // T + } +} + +function f22(x: T) { + if (x !== undefined) { + x; // T & {} + } + else { + x; // T + } + if (x !== null) { + x; // T + } + else { + x; // T + } + if (x !== undefined && x !== null) { + x; // T & {} + } + else { + x; // T + } + if (x != undefined) { + x; // T & {} + } + else { + x; // T + } + if (x != null) { + x; // T & {} + } + else { + x; // T + } +} + +function f23(x: T | undefined | null) { + if (x !== undefined) { + x; // T & {} | null + } + if (x !== null) { + x; // T & {} | undefined + } + if (x != undefined) { + x; // T & {} + } + if (x != null) { + x; // T & {} + } +} + +function f30(x: {}) { + if (typeof x === "object") { + x; // object + } +} + +function f31(x: T) { + if (typeof x === "object") { + x; // T & object | T & null + } + if (x && typeof x === "object") { + x; // T & object + } + if (typeof x === "object" && x) { + x; // T & object + } +} + +function f32(x: T) { + if (typeof x === "object") { + x; // T & object + } +} + +function possiblyNull(x: T) { + return !!true ? x : null; // T | null +} + +function possiblyUndefined(x: T) { + return !!true ? x : undefined; // T | undefined +} + +function possiblyNullOrUndefined(x: T) { + return possiblyUndefined(possiblyNull(x)); // T | null | undefined +} + +function ensureNotNull(x: T) { + if (x === null) throw Error(); + return x; // T & ({} | undefined) +} + +function ensureNotUndefined(x: T) { + if (x === undefined) throw Error(); + return x; // T & ({} | null) +} + +function ensureNotNullOrUndefined(x: T) { + return ensureNotUndefined(ensureNotNull(x)); // T & {} +} + +function f40(a: string | undefined, b: number | null | undefined) { + let a1 = ensureNotNullOrUndefined(a); // string + let b1 = ensureNotNullOrUndefined(b); // number +} + +type QQ = NonNullable>>; + +function f41(a: T) { + let a1 = ensureNotUndefined(ensureNotNull(a)); // T & {} + let a2 = ensureNotNull(ensureNotUndefined(a)); // T & {} + let a3 = ensureNotNull(ensureNotNull(a)); // T & {} | T & undefined + let a4 = ensureNotUndefined(ensureNotUndefined(a)); // T & {} | T & null + let a5 = ensureNotNullOrUndefined(ensureNotNullOrUndefined(a)); // T & {} + let a6 = ensureNotNull(possiblyNullOrUndefined(a)); // T & {} | undefined + let a7 = ensureNotUndefined(possiblyNullOrUndefined(a)); // T & {} | null + let a8 = ensureNotNull(possiblyUndefined(a)); // T & {} | undefined + let a9 = ensureNotUndefined(possiblyNull(a)); // T & {} | null +} + +// Repro from #48468 + +function deepEquals(a: T, b: T): boolean { + if (typeof a !== 'object' || typeof b !== 'object' || !a || !b) { + return false; + } + if (Array.isArray(a) || Array.isArray(b)) { + return false; + } + if (Object.keys(a).length !== Object.keys(b).length) { // Error here + return false; + } + return true; +} + + +//// [unknownControlFlow.js] +"use strict"; +function f01(u) { + var x1 = u; // Error + var x2 = u; + var x3 = u; + var x4 = u; +} +function f10(x) { + if (x) { + x; // {} + } + else { + x; // unknown + } + if (!x) { + x; // unknown + } + else { + x; // {} + } +} +function f11(x) { + if (x) { + x; // T & {} + } + else { + x; // T + } + if (!x) { + x; // T + } + else { + x; // T & {} + } +} +function f12(x) { + if (x) { + x; // T + } + else { + x; // T + } +} +function f20(x) { + if (x !== undefined) { + x; // {} | null + } + else { + x; // undefined + } + if (x !== null) { + x; // {} | undefined + } + else { + x; // null + } + if (x !== undefined && x !== null) { + x; // {} + } + else { + x; // null | undefined + } + if (x != undefined) { + x; // {} + } + else { + x; // null | undefined + } + if (x != null) { + x; // {} + } + else { + x; // null | undefined + } +} +function f21(x) { + if (x !== undefined) { + x; // T & ({} | null) + } + else { + x; // T + } + if (x !== null) { + x; // T & ({} | undefined) + } + else { + x; // T + } + if (x !== undefined && x !== null) { + x; // T & {} + } + else { + x; // T + } + if (x != undefined) { + x; // T & {} + } + else { + x; // T + } + if (x != null) { + x; // T & {} + } + else { + x; // T + } +} +function f22(x) { + if (x !== undefined) { + x; // T & {} + } + else { + x; // T + } + if (x !== null) { + x; // T + } + else { + x; // T + } + if (x !== undefined && x !== null) { + x; // T & {} + } + else { + x; // T + } + if (x != undefined) { + x; // T & {} + } + else { + x; // T + } + if (x != null) { + x; // T & {} + } + else { + x; // T + } +} +function f23(x) { + if (x !== undefined) { + x; // T & {} | null + } + if (x !== null) { + x; // T & {} | undefined + } + if (x != undefined) { + x; // T & {} + } + if (x != null) { + x; // T & {} + } +} +function f30(x) { + if (typeof x === "object") { + x; // object + } +} +function f31(x) { + if (typeof x === "object") { + x; // T & object | T & null + } + if (x && typeof x === "object") { + x; // T & object + } + if (typeof x === "object" && x) { + x; // T & object + } +} +function f32(x) { + if (typeof x === "object") { + x; // T & object + } +} +function possiblyNull(x) { + return !!true ? x : null; // T | null +} +function possiblyUndefined(x) { + return !!true ? x : undefined; // T | undefined +} +function possiblyNullOrUndefined(x) { + return possiblyUndefined(possiblyNull(x)); // T | null | undefined +} +function ensureNotNull(x) { + if (x === null) + throw Error(); + return x; // T & ({} | undefined) +} +function ensureNotUndefined(x) { + if (x === undefined) + throw Error(); + return x; // T & ({} | null) +} +function ensureNotNullOrUndefined(x) { + return ensureNotUndefined(ensureNotNull(x)); // T & {} +} +function f40(a, b) { + var a1 = ensureNotNullOrUndefined(a); // string + var b1 = ensureNotNullOrUndefined(b); // number +} +function f41(a) { + var a1 = ensureNotUndefined(ensureNotNull(a)); // T & {} + var a2 = ensureNotNull(ensureNotUndefined(a)); // T & {} + var a3 = ensureNotNull(ensureNotNull(a)); // T & {} | T & undefined + var a4 = ensureNotUndefined(ensureNotUndefined(a)); // T & {} | T & null + var a5 = ensureNotNullOrUndefined(ensureNotNullOrUndefined(a)); // T & {} + var a6 = ensureNotNull(possiblyNullOrUndefined(a)); // T & {} | undefined + var a7 = ensureNotUndefined(possiblyNullOrUndefined(a)); // T & {} | null + var a8 = ensureNotNull(possiblyUndefined(a)); // T & {} | undefined + var a9 = ensureNotUndefined(possiblyNull(a)); // T & {} | null +} +// Repro from #48468 +function deepEquals(a, b) { + if (typeof a !== 'object' || typeof b !== 'object' || !a || !b) { + return false; + } + if (Array.isArray(a) || Array.isArray(b)) { + return false; + } + if (Object.keys(a).length !== Object.keys(b).length) { // Error here + return false; + } + return true; +} + + +//// [unknownControlFlow.d.ts] +declare type T01 = {} & string; +declare type T02 = {} & 'a'; +declare type T03 = {} & object; +declare type T04 = {} & { + x: number; +}; +declare type T05 = {} & null; +declare type T06 = {} & undefined; +declare type T07 = undefined & void; +declare type T10 = string & {}; +declare type T11 = number & {}; +declare type T12 = bigint & {}; +declare type ThisNode = {}; +declare type ThatNode = {}; +declare type ThisOrThatNode = ThisNode | ThatNode; +declare function f01(u: unknown): void; +declare function f10(x: unknown): void; +declare function f11(x: T): void; +declare function f12(x: T): void; +declare function f20(x: unknown): void; +declare function f21(x: T): void; +declare function f22(x: T): void; +declare function f23(x: T | undefined | null): void; +declare function f30(x: {}): void; +declare function f31(x: T): void; +declare function f32(x: T): void; +declare function possiblyNull(x: T): T | null; +declare function possiblyUndefined(x: T): T | undefined; +declare function possiblyNullOrUndefined(x: T): T | null | undefined; +declare function ensureNotNull(x: T): T & ({} | undefined); +declare function ensureNotUndefined(x: T): T & ({} | null); +declare function ensureNotNullOrUndefined(x: T): T & {}; +declare function f40(a: string | undefined, b: number | null | undefined): void; +declare type QQ = NonNullable>>; +declare function f41(a: T): void; +declare function deepEquals(a: T, b: T): boolean; diff --git a/tests/baselines/reference/unknownControlFlow.symbols b/tests/baselines/reference/unknownControlFlow.symbols new file mode 100644 index 00000000000..eb938f3d406 --- /dev/null +++ b/tests/baselines/reference/unknownControlFlow.symbols @@ -0,0 +1,618 @@ +=== tests/cases/conformance/types/unknown/unknownControlFlow.ts === +type T01 = {} & string; // string +>T01 : Symbol(T01, Decl(unknownControlFlow.ts, 0, 0)) + +type T02 = {} & 'a'; // 'a' +>T02 : Symbol(T02, Decl(unknownControlFlow.ts, 0, 23)) + +type T03 = {} & object; // object +>T03 : Symbol(T03, Decl(unknownControlFlow.ts, 1, 20)) + +type T04 = {} & { x: number }; // { x: number } +>T04 : Symbol(T04, Decl(unknownControlFlow.ts, 2, 23)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 3, 17)) + +type T05 = {} & null; // never +>T05 : Symbol(T05, Decl(unknownControlFlow.ts, 3, 30)) + +type T06 = {} & undefined; // never +>T06 : Symbol(T06, Decl(unknownControlFlow.ts, 4, 21)) + +type T07 = undefined & void; // undefined +>T07 : Symbol(T07, Decl(unknownControlFlow.ts, 5, 26)) + +type T10 = string & {}; // Specially preserved +>T10 : Symbol(T10, Decl(unknownControlFlow.ts, 6, 28)) + +type T11 = number & {}; // Specially preserved +>T11 : Symbol(T11, Decl(unknownControlFlow.ts, 8, 23)) + +type T12 = bigint & {}; // Specially preserved +>T12 : Symbol(T12, Decl(unknownControlFlow.ts, 9, 23)) + +type ThisNode = {}; +>ThisNode : Symbol(ThisNode, Decl(unknownControlFlow.ts, 10, 23)) + +type ThatNode = {}; +>ThatNode : Symbol(ThatNode, Decl(unknownControlFlow.ts, 12, 19)) + +type ThisOrThatNode = ThisNode | ThatNode; +>ThisOrThatNode : Symbol(ThisOrThatNode, Decl(unknownControlFlow.ts, 13, 19)) +>ThisNode : Symbol(ThisNode, Decl(unknownControlFlow.ts, 10, 23)) +>ThatNode : Symbol(ThatNode, Decl(unknownControlFlow.ts, 12, 19)) + +function f01(u: unknown) { +>f01 : Symbol(f01, Decl(unknownControlFlow.ts, 14, 42)) +>u : Symbol(u, Decl(unknownControlFlow.ts, 16, 13)) + + let x1: {} = u; // Error +>x1 : Symbol(x1, Decl(unknownControlFlow.ts, 17, 7)) +>u : Symbol(u, Decl(unknownControlFlow.ts, 16, 13)) + + let x2: {} | null | undefined = u; +>x2 : Symbol(x2, Decl(unknownControlFlow.ts, 18, 7)) +>u : Symbol(u, Decl(unknownControlFlow.ts, 16, 13)) + + let x3: {} | { x: string } | null | undefined = u; +>x3 : Symbol(x3, Decl(unknownControlFlow.ts, 19, 7)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 19, 18)) +>u : Symbol(u, Decl(unknownControlFlow.ts, 16, 13)) + + let x4: ThisOrThatNode | null | undefined = u; +>x4 : Symbol(x4, Decl(unknownControlFlow.ts, 20, 7)) +>ThisOrThatNode : Symbol(ThisOrThatNode, Decl(unknownControlFlow.ts, 13, 19)) +>u : Symbol(u, Decl(unknownControlFlow.ts, 16, 13)) +} + +function f10(x: unknown) { +>f10 : Symbol(f10, Decl(unknownControlFlow.ts, 21, 1)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 23, 13)) + + if (x) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 23, 13)) + + x; // {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 23, 13)) + } + else { + x; // unknown +>x : Symbol(x, Decl(unknownControlFlow.ts, 23, 13)) + } + if (!x) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 23, 13)) + + x; // unknown +>x : Symbol(x, Decl(unknownControlFlow.ts, 23, 13)) + } + else { + x; // {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 23, 13)) + } +} + +function f11(x: T) { +>f11 : Symbol(f11, Decl(unknownControlFlow.ts, 36, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 38, 13)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 38, 16)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 38, 13)) + + if (x) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 38, 16)) + + x; // T & {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 38, 16)) + } + else { + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 38, 16)) + } + if (!x) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 38, 16)) + + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 38, 16)) + } + else { + x; // T & {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 38, 16)) + } +} + +function f12(x: T) { +>f12 : Symbol(f12, Decl(unknownControlFlow.ts, 51, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 53, 13)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 53, 27)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 53, 13)) + + if (x) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 53, 27)) + + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 53, 27)) + } + else { + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 53, 27)) + } +} + +function f20(x: unknown) { +>f20 : Symbol(f20, Decl(unknownControlFlow.ts, 60, 1)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + + if (x !== undefined) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) +>undefined : Symbol(undefined) + + x; // {} | null +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + } + else { + x; // undefined +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + } + if (x !== null) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + + x; // {} | undefined +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + } + else { + x; // null +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + } + if (x !== undefined && x !== null) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) +>undefined : Symbol(undefined) +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + + x; // {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + } + else { + x; // null | undefined +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + } + if (x != undefined) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) +>undefined : Symbol(undefined) + + x; // {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + } + else { + x; // null | undefined +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + } + if (x != null) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + + x; // {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + } + else { + x; // null | undefined +>x : Symbol(x, Decl(unknownControlFlow.ts, 62, 13)) + } +} + +function f21(x: T) { +>f21 : Symbol(f21, Decl(unknownControlFlow.ts, 93, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 95, 13)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 95, 13)) + + if (x !== undefined) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) +>undefined : Symbol(undefined) + + x; // T & ({} | null) +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + } + else { + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + } + if (x !== null) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + + x; // T & ({} | undefined) +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + } + else { + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + } + if (x !== undefined && x !== null) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) +>undefined : Symbol(undefined) +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + + x; // T & {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + } + else { + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + } + if (x != undefined) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) +>undefined : Symbol(undefined) + + x; // T & {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + } + else { + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + } + if (x != null) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + + x; // T & {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + } + else { + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 95, 16)) + } +} + +function f22(x: T) { +>f22 : Symbol(f22, Decl(unknownControlFlow.ts, 126, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 128, 13)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 128, 13)) + + if (x !== undefined) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) +>undefined : Symbol(undefined) + + x; // T & {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + } + else { + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + } + if (x !== null) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + } + else { + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + } + if (x !== undefined && x !== null) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) +>undefined : Symbol(undefined) +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + + x; // T & {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + } + else { + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + } + if (x != undefined) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) +>undefined : Symbol(undefined) + + x; // T & {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + } + else { + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + } + if (x != null) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + + x; // T & {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + } + else { + x; // T +>x : Symbol(x, Decl(unknownControlFlow.ts, 128, 39)) + } +} + +function f23(x: T | undefined | null) { +>f23 : Symbol(f23, Decl(unknownControlFlow.ts, 159, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 161, 13)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 161, 16)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 161, 13)) + + if (x !== undefined) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 161, 16)) +>undefined : Symbol(undefined) + + x; // T & {} | null +>x : Symbol(x, Decl(unknownControlFlow.ts, 161, 16)) + } + if (x !== null) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 161, 16)) + + x; // T & {} | undefined +>x : Symbol(x, Decl(unknownControlFlow.ts, 161, 16)) + } + if (x != undefined) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 161, 16)) +>undefined : Symbol(undefined) + + x; // T & {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 161, 16)) + } + if (x != null) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 161, 16)) + + x; // T & {} +>x : Symbol(x, Decl(unknownControlFlow.ts, 161, 16)) + } +} + +function f30(x: {}) { +>f30 : Symbol(f30, Decl(unknownControlFlow.ts, 174, 1)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 176, 13)) + + if (typeof x === "object") { +>x : Symbol(x, Decl(unknownControlFlow.ts, 176, 13)) + + x; // object +>x : Symbol(x, Decl(unknownControlFlow.ts, 176, 13)) + } +} + +function f31(x: T) { +>f31 : Symbol(f31, Decl(unknownControlFlow.ts, 180, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 182, 13)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 182, 16)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 182, 13)) + + if (typeof x === "object") { +>x : Symbol(x, Decl(unknownControlFlow.ts, 182, 16)) + + x; // T & object | T & null +>x : Symbol(x, Decl(unknownControlFlow.ts, 182, 16)) + } + if (x && typeof x === "object") { +>x : Symbol(x, Decl(unknownControlFlow.ts, 182, 16)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 182, 16)) + + x; // T & object +>x : Symbol(x, Decl(unknownControlFlow.ts, 182, 16)) + } + if (typeof x === "object" && x) { +>x : Symbol(x, Decl(unknownControlFlow.ts, 182, 16)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 182, 16)) + + x; // T & object +>x : Symbol(x, Decl(unknownControlFlow.ts, 182, 16)) + } +} + +function f32(x: T) { +>f32 : Symbol(f32, Decl(unknownControlFlow.ts, 192, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 194, 13)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 194, 39)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 194, 13)) + + if (typeof x === "object") { +>x : Symbol(x, Decl(unknownControlFlow.ts, 194, 39)) + + x; // T & object +>x : Symbol(x, Decl(unknownControlFlow.ts, 194, 39)) + } +} + +function possiblyNull(x: T) { +>possiblyNull : Symbol(possiblyNull, Decl(unknownControlFlow.ts, 198, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 200, 22)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 200, 25)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 200, 22)) + + return !!true ? x : null; // T | null +>x : Symbol(x, Decl(unknownControlFlow.ts, 200, 25)) +} + +function possiblyUndefined(x: T) { +>possiblyUndefined : Symbol(possiblyUndefined, Decl(unknownControlFlow.ts, 202, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 204, 27)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 204, 30)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 204, 27)) + + return !!true ? x : undefined; // T | undefined +>x : Symbol(x, Decl(unknownControlFlow.ts, 204, 30)) +>undefined : Symbol(undefined) +} + +function possiblyNullOrUndefined(x: T) { +>possiblyNullOrUndefined : Symbol(possiblyNullOrUndefined, Decl(unknownControlFlow.ts, 206, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 208, 33)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 208, 36)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 208, 33)) + + return possiblyUndefined(possiblyNull(x)); // T | null | undefined +>possiblyUndefined : Symbol(possiblyUndefined, Decl(unknownControlFlow.ts, 202, 1)) +>possiblyNull : Symbol(possiblyNull, Decl(unknownControlFlow.ts, 198, 1)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 208, 36)) +} + +function ensureNotNull(x: T) { +>ensureNotNull : Symbol(ensureNotNull, Decl(unknownControlFlow.ts, 210, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 212, 23)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 212, 26)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 212, 23)) + + if (x === null) throw Error(); +>x : Symbol(x, Decl(unknownControlFlow.ts, 212, 26)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + return x; // T & ({} | undefined) +>x : Symbol(x, Decl(unknownControlFlow.ts, 212, 26)) +} + +function ensureNotUndefined(x: T) { +>ensureNotUndefined : Symbol(ensureNotUndefined, Decl(unknownControlFlow.ts, 215, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 217, 28)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 217, 31)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 217, 28)) + + if (x === undefined) throw Error(); +>x : Symbol(x, Decl(unknownControlFlow.ts, 217, 31)) +>undefined : Symbol(undefined) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + return x; // T & ({} | null) +>x : Symbol(x, Decl(unknownControlFlow.ts, 217, 31)) +} + +function ensureNotNullOrUndefined(x: T) { +>ensureNotNullOrUndefined : Symbol(ensureNotNullOrUndefined, Decl(unknownControlFlow.ts, 220, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 222, 34)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 222, 37)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 222, 34)) + + return ensureNotUndefined(ensureNotNull(x)); // T & {} +>ensureNotUndefined : Symbol(ensureNotUndefined, Decl(unknownControlFlow.ts, 215, 1)) +>ensureNotNull : Symbol(ensureNotNull, Decl(unknownControlFlow.ts, 210, 1)) +>x : Symbol(x, Decl(unknownControlFlow.ts, 222, 37)) +} + +function f40(a: string | undefined, b: number | null | undefined) { +>f40 : Symbol(f40, Decl(unknownControlFlow.ts, 224, 1)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 226, 13)) +>b : Symbol(b, Decl(unknownControlFlow.ts, 226, 35)) + + let a1 = ensureNotNullOrUndefined(a); // string +>a1 : Symbol(a1, Decl(unknownControlFlow.ts, 227, 7)) +>ensureNotNullOrUndefined : Symbol(ensureNotNullOrUndefined, Decl(unknownControlFlow.ts, 220, 1)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 226, 13)) + + let b1 = ensureNotNullOrUndefined(b); // number +>b1 : Symbol(b1, Decl(unknownControlFlow.ts, 228, 7)) +>ensureNotNullOrUndefined : Symbol(ensureNotNullOrUndefined, Decl(unknownControlFlow.ts, 220, 1)) +>b : Symbol(b, Decl(unknownControlFlow.ts, 226, 35)) +} + +type QQ = NonNullable>>; +>QQ : Symbol(QQ, Decl(unknownControlFlow.ts, 229, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 231, 8)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 231, 8)) + +function f41(a: T) { +>f41 : Symbol(f41, Decl(unknownControlFlow.ts, 231, 54)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 233, 13)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 233, 16)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 233, 13)) + + let a1 = ensureNotUndefined(ensureNotNull(a)); // T & {} +>a1 : Symbol(a1, Decl(unknownControlFlow.ts, 234, 7)) +>ensureNotUndefined : Symbol(ensureNotUndefined, Decl(unknownControlFlow.ts, 215, 1)) +>ensureNotNull : Symbol(ensureNotNull, Decl(unknownControlFlow.ts, 210, 1)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 233, 16)) + + let a2 = ensureNotNull(ensureNotUndefined(a)); // T & {} +>a2 : Symbol(a2, Decl(unknownControlFlow.ts, 235, 7)) +>ensureNotNull : Symbol(ensureNotNull, Decl(unknownControlFlow.ts, 210, 1)) +>ensureNotUndefined : Symbol(ensureNotUndefined, Decl(unknownControlFlow.ts, 215, 1)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 233, 16)) + + let a3 = ensureNotNull(ensureNotNull(a)); // T & {} | T & undefined +>a3 : Symbol(a3, Decl(unknownControlFlow.ts, 236, 7)) +>ensureNotNull : Symbol(ensureNotNull, Decl(unknownControlFlow.ts, 210, 1)) +>ensureNotNull : Symbol(ensureNotNull, Decl(unknownControlFlow.ts, 210, 1)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 233, 16)) + + let a4 = ensureNotUndefined(ensureNotUndefined(a)); // T & {} | T & null +>a4 : Symbol(a4, Decl(unknownControlFlow.ts, 237, 7)) +>ensureNotUndefined : Symbol(ensureNotUndefined, Decl(unknownControlFlow.ts, 215, 1)) +>ensureNotUndefined : Symbol(ensureNotUndefined, Decl(unknownControlFlow.ts, 215, 1)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 233, 16)) + + let a5 = ensureNotNullOrUndefined(ensureNotNullOrUndefined(a)); // T & {} +>a5 : Symbol(a5, Decl(unknownControlFlow.ts, 238, 7)) +>ensureNotNullOrUndefined : Symbol(ensureNotNullOrUndefined, Decl(unknownControlFlow.ts, 220, 1)) +>ensureNotNullOrUndefined : Symbol(ensureNotNullOrUndefined, Decl(unknownControlFlow.ts, 220, 1)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 233, 16)) + + let a6 = ensureNotNull(possiblyNullOrUndefined(a)); // T & {} | undefined +>a6 : Symbol(a6, Decl(unknownControlFlow.ts, 239, 7)) +>ensureNotNull : Symbol(ensureNotNull, Decl(unknownControlFlow.ts, 210, 1)) +>possiblyNullOrUndefined : Symbol(possiblyNullOrUndefined, Decl(unknownControlFlow.ts, 206, 1)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 233, 16)) + + let a7 = ensureNotUndefined(possiblyNullOrUndefined(a)); // T & {} | null +>a7 : Symbol(a7, Decl(unknownControlFlow.ts, 240, 7)) +>ensureNotUndefined : Symbol(ensureNotUndefined, Decl(unknownControlFlow.ts, 215, 1)) +>possiblyNullOrUndefined : Symbol(possiblyNullOrUndefined, Decl(unknownControlFlow.ts, 206, 1)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 233, 16)) + + let a8 = ensureNotNull(possiblyUndefined(a)); // T & {} | undefined +>a8 : Symbol(a8, Decl(unknownControlFlow.ts, 241, 7)) +>ensureNotNull : Symbol(ensureNotNull, Decl(unknownControlFlow.ts, 210, 1)) +>possiblyUndefined : Symbol(possiblyUndefined, Decl(unknownControlFlow.ts, 202, 1)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 233, 16)) + + let a9 = ensureNotUndefined(possiblyNull(a)); // T & {} | null +>a9 : Symbol(a9, Decl(unknownControlFlow.ts, 242, 7)) +>ensureNotUndefined : Symbol(ensureNotUndefined, Decl(unknownControlFlow.ts, 215, 1)) +>possiblyNull : Symbol(possiblyNull, Decl(unknownControlFlow.ts, 198, 1)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 233, 16)) +} + +// Repro from #48468 + +function deepEquals(a: T, b: T): boolean { +>deepEquals : Symbol(deepEquals, Decl(unknownControlFlow.ts, 243, 1)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 247, 20)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 247, 23)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 247, 20)) +>b : Symbol(b, Decl(unknownControlFlow.ts, 247, 28)) +>T : Symbol(T, Decl(unknownControlFlow.ts, 247, 20)) + + if (typeof a !== 'object' || typeof b !== 'object' || !a || !b) { +>a : Symbol(a, Decl(unknownControlFlow.ts, 247, 23)) +>b : Symbol(b, Decl(unknownControlFlow.ts, 247, 28)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 247, 23)) +>b : Symbol(b, Decl(unknownControlFlow.ts, 247, 28)) + + return false; + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 247, 23)) +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(unknownControlFlow.ts, 247, 28)) + + return false; + } + if (Object.keys(a).length !== Object.keys(b).length) { // Error here +>Object.keys(a).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(unknownControlFlow.ts, 247, 23)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>Object.keys(b).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(unknownControlFlow.ts, 247, 28)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + return false; + } + return true; +} + diff --git a/tests/baselines/reference/unknownControlFlow.types b/tests/baselines/reference/unknownControlFlow.types new file mode 100644 index 00000000000..13633b8c7fb --- /dev/null +++ b/tests/baselines/reference/unknownControlFlow.types @@ -0,0 +1,699 @@ +=== tests/cases/conformance/types/unknown/unknownControlFlow.ts === +type T01 = {} & string; // string +>T01 : string + +type T02 = {} & 'a'; // 'a' +>T02 : "a" + +type T03 = {} & object; // object +>T03 : object + +type T04 = {} & { x: number }; // { x: number } +>T04 : { x: number; } +>x : number + +type T05 = {} & null; // never +>T05 : never +>null : null + +type T06 = {} & undefined; // never +>T06 : never + +type T07 = undefined & void; // undefined +>T07 : undefined + +type T10 = string & {}; // Specially preserved +>T10 : string & {} + +type T11 = number & {}; // Specially preserved +>T11 : number & {} + +type T12 = bigint & {}; // Specially preserved +>T12 : bigint & {} + +type ThisNode = {}; +>ThisNode : {} + +type ThatNode = {}; +>ThatNode : {} + +type ThisOrThatNode = ThisNode | ThatNode; +>ThisOrThatNode : ThisNode | ThatNode + +function f01(u: unknown) { +>f01 : (u: unknown) => void +>u : unknown + + let x1: {} = u; // Error +>x1 : {} +>u : unknown + + let x2: {} | null | undefined = u; +>x2 : {} | null | undefined +>null : null +>u : unknown + + let x3: {} | { x: string } | null | undefined = u; +>x3 : {} | { x: string; } | null | undefined +>x : string +>null : null +>u : unknown + + let x4: ThisOrThatNode | null | undefined = u; +>x4 : ThisOrThatNode | null | undefined +>null : null +>u : unknown +} + +function f10(x: unknown) { +>f10 : (x: unknown) => void +>x : unknown + + if (x) { +>x : unknown + + x; // {} +>x : {} + } + else { + x; // unknown +>x : unknown + } + if (!x) { +>!x : boolean +>x : unknown + + x; // unknown +>x : unknown + } + else { + x; // {} +>x : {} + } +} + +function f11(x: T) { +>f11 : (x: T) => void +>x : T + + if (x) { +>x : T + + x; // T & {} +>x : NonNullable + } + else { + x; // T +>x : T + } + if (!x) { +>!x : boolean +>x : T + + x; // T +>x : T + } + else { + x; // T & {} +>x : NonNullable + } +} + +function f12(x: T) { +>f12 : (x: T) => void +>x : T + + if (x) { +>x : T + + x; // T +>x : T + } + else { + x; // T +>x : T + } +} + +function f20(x: unknown) { +>f20 : (x: unknown) => void +>x : unknown + + if (x !== undefined) { +>x !== undefined : boolean +>x : unknown +>undefined : undefined + + x; // {} | null +>x : {} | null + } + else { + x; // undefined +>x : undefined + } + if (x !== null) { +>x !== null : boolean +>x : unknown +>null : null + + x; // {} | undefined +>x : {} | undefined + } + else { + x; // null +>x : null + } + if (x !== undefined && x !== null) { +>x !== undefined && x !== null : boolean +>x !== undefined : boolean +>x : unknown +>undefined : undefined +>x !== null : boolean +>x : {} | null +>null : null + + x; // {} +>x : {} + } + else { + x; // null | undefined +>x : null | undefined + } + if (x != undefined) { +>x != undefined : boolean +>x : unknown +>undefined : undefined + + x; // {} +>x : {} + } + else { + x; // null | undefined +>x : null | undefined + } + if (x != null) { +>x != null : boolean +>x : unknown +>null : null + + x; // {} +>x : {} + } + else { + x; // null | undefined +>x : null | undefined + } +} + +function f21(x: T) { +>f21 : (x: T) => void +>x : T + + if (x !== undefined) { +>x !== undefined : boolean +>x : T +>undefined : undefined + + x; // T & ({} | null) +>x : T & ({} | null) + } + else { + x; // T +>x : T + } + if (x !== null) { +>x !== null : boolean +>x : T +>null : null + + x; // T & ({} | undefined) +>x : T & ({} | undefined) + } + else { + x; // T +>x : T + } + if (x !== undefined && x !== null) { +>x !== undefined && x !== null : boolean +>x !== undefined : boolean +>x : T +>undefined : undefined +>x !== null : boolean +>x : T & ({} | null) +>null : null + + x; // T & {} +>x : T & {} + } + else { + x; // T +>x : T + } + if (x != undefined) { +>x != undefined : boolean +>x : T +>undefined : undefined + + x; // T & {} +>x : NonNullable + } + else { + x; // T +>x : T + } + if (x != null) { +>x != null : boolean +>x : T +>null : null + + x; // T & {} +>x : NonNullable + } + else { + x; // T +>x : T + } +} + +function f22(x: T) { +>f22 : (x: T) => void +>x : T + + if (x !== undefined) { +>x !== undefined : boolean +>x : T +>undefined : undefined + + x; // T & {} +>x : T & {} + } + else { + x; // T +>x : T + } + if (x !== null) { +>x !== null : boolean +>x : T +>null : null + + x; // T +>x : T + } + else { + x; // T +>x : never + } + if (x !== undefined && x !== null) { +>x !== undefined && x !== null : boolean +>x !== undefined : boolean +>x : T +>undefined : undefined +>x !== null : boolean +>x : T & {} +>null : null + + x; // T & {} +>x : T & {} + } + else { + x; // T +>x : T + } + if (x != undefined) { +>x != undefined : boolean +>x : T +>undefined : undefined + + x; // T & {} +>x : NonNullable + } + else { + x; // T +>x : T + } + if (x != null) { +>x != null : boolean +>x : T +>null : null + + x; // T & {} +>x : NonNullable + } + else { + x; // T +>x : T + } +} + +function f23(x: T | undefined | null) { +>f23 : (x: T | undefined | null) => void +>x : T | null | undefined +>null : null + + if (x !== undefined) { +>x !== undefined : boolean +>x : T | null | undefined +>undefined : undefined + + x; // T & {} | null +>x : (T & {}) | null + } + if (x !== null) { +>x !== null : boolean +>x : T | null | undefined +>null : null + + x; // T & {} | undefined +>x : (T & {}) | undefined + } + if (x != undefined) { +>x != undefined : boolean +>x : T | null | undefined +>undefined : undefined + + x; // T & {} +>x : NonNullable + } + if (x != null) { +>x != null : boolean +>x : T | null | undefined +>null : null + + x; // T & {} +>x : NonNullable + } +} + +function f30(x: {}) { +>f30 : (x: {}) => void +>x : {} + + if (typeof x === "object") { +>typeof x === "object" : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : {} +>"object" : "object" + + x; // object +>x : object + } +} + +function f31(x: T) { +>f31 : (x: T) => void +>x : T + + if (typeof x === "object") { +>typeof x === "object" : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : T +>"object" : "object" + + x; // T & object | T & null +>x : (T & null) | (T & object) + } + if (x && typeof x === "object") { +>x && typeof x === "object" : boolean +>x : T +>typeof x === "object" : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : NonNullable +>"object" : "object" + + x; // T & object +>x : T & object + } + if (typeof x === "object" && x) { +>typeof x === "object" && x : false | (T & null) | (T & object) +>typeof x === "object" : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : T +>"object" : "object" +>x : (T & null) | (T & object) + + x; // T & object +>x : T & object + } +} + +function f32(x: T) { +>f32 : (x: T) => void +>x : T + + if (typeof x === "object") { +>typeof x === "object" : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : T +>"object" : "object" + + x; // T & object +>x : T & object + } +} + +function possiblyNull(x: T) { +>possiblyNull : (x: T) => T | null +>x : T + + return !!true ? x : null; // T | null +>!!true ? x : null : T | null +>!!true : true +>!true : false +>true : true +>x : T +>null : null +} + +function possiblyUndefined(x: T) { +>possiblyUndefined : (x: T) => T | undefined +>x : T + + return !!true ? x : undefined; // T | undefined +>!!true ? x : undefined : T | undefined +>!!true : true +>!true : false +>true : true +>x : T +>undefined : undefined +} + +function possiblyNullOrUndefined(x: T) { +>possiblyNullOrUndefined : (x: T) => T | null | undefined +>x : T + + return possiblyUndefined(possiblyNull(x)); // T | null | undefined +>possiblyUndefined(possiblyNull(x)) : T | null | undefined +>possiblyUndefined : (x: T) => T | undefined +>possiblyNull(x) : T | null +>possiblyNull : (x: T) => T | null +>x : T +} + +function ensureNotNull(x: T) { +>ensureNotNull : (x: T) => T & ({} | undefined) +>x : T + + if (x === null) throw Error(); +>x === null : boolean +>x : T +>null : null +>Error() : Error +>Error : ErrorConstructor + + return x; // T & ({} | undefined) +>x : T & ({} | undefined) +} + +function ensureNotUndefined(x: T) { +>ensureNotUndefined : (x: T) => T & ({} | null) +>x : T + + if (x === undefined) throw Error(); +>x === undefined : boolean +>x : T +>undefined : undefined +>Error() : Error +>Error : ErrorConstructor + + return x; // T & ({} | null) +>x : T & ({} | null) +} + +function ensureNotNullOrUndefined(x: T) { +>ensureNotNullOrUndefined : (x: T) => T & {} +>x : T + + return ensureNotUndefined(ensureNotNull(x)); // T & {} +>ensureNotUndefined(ensureNotNull(x)) : T & {} +>ensureNotUndefined : (x: T) => T & ({} | null) +>ensureNotNull(x) : T & ({} | undefined) +>ensureNotNull : (x: T) => T & ({} | undefined) +>x : T +} + +function f40(a: string | undefined, b: number | null | undefined) { +>f40 : (a: string | undefined, b: number | null | undefined) => void +>a : string | undefined +>b : number | null | undefined +>null : null + + let a1 = ensureNotNullOrUndefined(a); // string +>a1 : string +>ensureNotNullOrUndefined(a) : string +>ensureNotNullOrUndefined : (x: T) => T & {} +>a : string | undefined + + let b1 = ensureNotNullOrUndefined(b); // number +>b1 : number +>ensureNotNullOrUndefined(b) : number +>ensureNotNullOrUndefined : (x: T) => T & {} +>b : number | null | undefined +} + +type QQ = NonNullable>>; +>QQ : QQ + +function f41(a: T) { +>f41 : (a: T) => void +>a : T + + let a1 = ensureNotUndefined(ensureNotNull(a)); // T & {} +>a1 : T & {} +>ensureNotUndefined(ensureNotNull(a)) : T & {} +>ensureNotUndefined : (x: T) => T & ({} | null) +>ensureNotNull(a) : T & ({} | undefined) +>ensureNotNull : (x: T) => T & ({} | undefined) +>a : T + + let a2 = ensureNotNull(ensureNotUndefined(a)); // T & {} +>a2 : T & {} +>ensureNotNull(ensureNotUndefined(a)) : T & {} +>ensureNotNull : (x: T) => T & ({} | undefined) +>ensureNotUndefined(a) : T & ({} | null) +>ensureNotUndefined : (x: T) => T & ({} | null) +>a : T + + let a3 = ensureNotNull(ensureNotNull(a)); // T & {} | T & undefined +>a3 : (T & undefined) | (T & {}) +>ensureNotNull(ensureNotNull(a)) : (T & undefined) | (T & {}) +>ensureNotNull : (x: T) => T & ({} | undefined) +>ensureNotNull(a) : T & ({} | undefined) +>ensureNotNull : (x: T) => T & ({} | undefined) +>a : T + + let a4 = ensureNotUndefined(ensureNotUndefined(a)); // T & {} | T & null +>a4 : (T & {}) | (T & null) +>ensureNotUndefined(ensureNotUndefined(a)) : (T & {}) | (T & null) +>ensureNotUndefined : (x: T) => T & ({} | null) +>ensureNotUndefined(a) : T & ({} | null) +>ensureNotUndefined : (x: T) => T & ({} | null) +>a : T + + let a5 = ensureNotNullOrUndefined(ensureNotNullOrUndefined(a)); // T & {} +>a5 : T & {} +>ensureNotNullOrUndefined(ensureNotNullOrUndefined(a)) : T & {} +>ensureNotNullOrUndefined : (x: T) => T & {} +>ensureNotNullOrUndefined(a) : T & {} +>ensureNotNullOrUndefined : (x: T) => T & {} +>a : T + + let a6 = ensureNotNull(possiblyNullOrUndefined(a)); // T & {} | undefined +>a6 : (T & {}) | undefined +>ensureNotNull(possiblyNullOrUndefined(a)) : (T & {}) | undefined +>ensureNotNull : (x: T) => T & ({} | undefined) +>possiblyNullOrUndefined(a) : T | null | undefined +>possiblyNullOrUndefined : (x: T) => T | null | undefined +>a : T + + let a7 = ensureNotUndefined(possiblyNullOrUndefined(a)); // T & {} | null +>a7 : (T & {}) | null +>ensureNotUndefined(possiblyNullOrUndefined(a)) : (T & {}) | null +>ensureNotUndefined : (x: T) => T & ({} | null) +>possiblyNullOrUndefined(a) : T | null | undefined +>possiblyNullOrUndefined : (x: T) => T | null | undefined +>a : T + + let a8 = ensureNotNull(possiblyUndefined(a)); // T & {} | undefined +>a8 : (T & {}) | undefined +>ensureNotNull(possiblyUndefined(a)) : (T & {}) | undefined +>ensureNotNull : (x: T) => T & ({} | undefined) +>possiblyUndefined(a) : T | undefined +>possiblyUndefined : (x: T) => T | undefined +>a : T + + let a9 = ensureNotUndefined(possiblyNull(a)); // T & {} | null +>a9 : (T & {}) | null +>ensureNotUndefined(possiblyNull(a)) : (T & {}) | null +>ensureNotUndefined : (x: T) => T & ({} | null) +>possiblyNull(a) : T | null +>possiblyNull : (x: T) => T | null +>a : T +} + +// Repro from #48468 + +function deepEquals(a: T, b: T): boolean { +>deepEquals : (a: T, b: T) => boolean +>a : T +>b : T + + if (typeof a !== 'object' || typeof b !== 'object' || !a || !b) { +>typeof a !== 'object' || typeof b !== 'object' || !a || !b : boolean +>typeof a !== 'object' || typeof b !== 'object' || !a : boolean +>typeof a !== 'object' || typeof b !== 'object' : boolean +>typeof a !== 'object' : boolean +>typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>a : T +>'object' : "object" +>typeof b !== 'object' : boolean +>typeof b : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>b : T +>'object' : "object" +>!a : boolean +>a : (T & null) | (T & object) +>!b : boolean +>b : (T & null) | (T & object) + + return false; +>false : false + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray(a) || Array.isArray(b) : boolean +>Array.isArray(a) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>a : T & object +>Array.isArray(b) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>b : T & object + + return false; +>false : false + } + if (Object.keys(a).length !== Object.keys(b).length) { // Error here +>Object.keys(a).length !== Object.keys(b).length : boolean +>Object.keys(a).length : number +>Object.keys(a) : string[] +>Object.keys : (o: object) => string[] +>Object : ObjectConstructor +>keys : (o: object) => string[] +>a : T & object +>length : number +>Object.keys(b).length : number +>Object.keys(b) : string[] +>Object.keys : (o: object) => string[] +>Object : ObjectConstructor +>keys : (o: object) => string[] +>b : T & object +>length : number + + return false; +>false : false + } + return true; +>true : true +} + diff --git a/tests/baselines/reference/unknownType1.errors.txt b/tests/baselines/reference/unknownType1.errors.txt index 342d0fbb706..a827753e5a2 100644 --- a/tests/baselines/reference/unknownType1.errors.txt +++ b/tests/baselines/reference/unknownType1.errors.txt @@ -14,7 +14,6 @@ tests/cases/conformance/types/unknown/unknownType1.ts(110,9): error TS2322: Type tests/cases/conformance/types/unknown/unknownType1.ts(111,9): error TS2322: Type 'unknown' is not assignable to type 'string'. tests/cases/conformance/types/unknown/unknownType1.ts(112,9): error TS2322: Type 'unknown' is not assignable to type 'string[]'. tests/cases/conformance/types/unknown/unknownType1.ts(113,9): error TS2322: Type 'unknown' is not assignable to type '{}'. -tests/cases/conformance/types/unknown/unknownType1.ts(114,9): error TS2322: Type 'unknown' is not assignable to type '{} | null | undefined'. tests/cases/conformance/types/unknown/unknownType1.ts(120,9): error TS2322: Type 'T' is not assignable to type 'object'. tests/cases/conformance/types/unknown/unknownType1.ts(128,5): error TS2322: Type 'number[]' is not assignable to type '{ [x: string]: unknown; }'. Index signature for type 'string' is missing in type 'number[]'. @@ -24,6 +23,7 @@ tests/cases/conformance/types/unknown/unknownType1.ts(144,29): error TS2698: Spr tests/cases/conformance/types/unknown/unknownType1.ts(150,17): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. tests/cases/conformance/types/unknown/unknownType1.ts(156,14): error TS2700: Rest types may only be created from object types. tests/cases/conformance/types/unknown/unknownType1.ts(162,5): error TS2564: Property 'a' has no initializer and is not definitely assigned in the constructor. +tests/cases/conformance/types/unknown/unknownType1.ts(170,9): error TS2322: Type 'T' is not assignable to type '{}'. tests/cases/conformance/types/unknown/unknownType1.ts(171,9): error TS2322: Type 'U' is not assignable to type '{}'. tests/cases/conformance/types/unknown/unknownType1.ts(181,5): error TS2322: Type 'T' is not assignable to type '{}'. @@ -175,8 +175,6 @@ tests/cases/conformance/types/unknown/unknownType1.ts(181,5): error TS2322: Type ~~ !!! error TS2322: Type 'unknown' is not assignable to type '{}'. let v7: {} | null | undefined = x; // Error - ~~ -!!! error TS2322: Type 'unknown' is not assignable to type '{} | null | undefined'. } // Type parameter 'T extends unknown' not related to object @@ -250,6 +248,9 @@ tests/cases/conformance/types/unknown/unknownType1.ts(181,5): error TS2322: Type function f30(t: T, u: U) { let x: {} = t; + ~ +!!! error TS2322: Type 'T' is not assignable to type '{}'. +!!! related TS2208 tests/cases/conformance/types/unknown/unknownType1.ts:169:14: This type parameter probably needs an `extends object` constraint. let y: {} = u; ~ !!! error TS2322: Type 'U' is not assignable to type '{}'. diff --git a/tests/baselines/reference/unknownType2.types b/tests/baselines/reference/unknownType2.types index cbb9269c763..634546bb5ff 100644 --- a/tests/baselines/reference/unknownType2.types +++ b/tests/baselines/reference/unknownType2.types @@ -640,7 +640,7 @@ function f2(x: unknown): string | undefined { >undefined : undefined >typeof x !== 'string' : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : unknown +>x : {} | null >'string' : "string" throw new Error(); diff --git a/tests/baselines/reference/voidUndefinedReduction.types b/tests/baselines/reference/voidUndefinedReduction.types index a11667bf476..8f8f54222d6 100644 --- a/tests/baselines/reference/voidUndefinedReduction.types +++ b/tests/baselines/reference/voidUndefinedReduction.types @@ -12,7 +12,7 @@ function isDefined(value: T | undefined | null | void): value is T { >value : void | T | null | undefined >undefined : undefined >value !== null : boolean ->value : T | null +>value : (T & {}) | null >null : null } diff --git a/tests/cases/compiler/declarationEmitMappedTypeTemplateTypeofSymbol.ts b/tests/cases/compiler/declarationEmitMappedTypeTemplateTypeofSymbol.ts new file mode 100644 index 00000000000..cc6118802d8 --- /dev/null +++ b/tests/cases/compiler/declarationEmitMappedTypeTemplateTypeofSymbol.ts @@ -0,0 +1,19 @@ +// @strict: true +// @declaration: true +// @filename: a.d.ts +export declare const timestampSymbol: unique symbol; + +export declare const Timestamp: { + [TKey in typeof timestampSymbol]: true; +}; + +export declare function now(): typeof Timestamp; + +// @filename: b.ts +import * as x from "./a"; +export const timestamp = x.now(); + +// @filename: c.ts +import { now } from "./a"; + +export const timestamp = now(); \ No newline at end of file diff --git a/tests/cases/compiler/interfacedeclWithIndexerErrors.ts b/tests/cases/compiler/interfacedeclWithIndexerErrors.ts index 4b836247796..054d5e044ac 100644 --- a/tests/cases/compiler/interfacedeclWithIndexerErrors.ts +++ b/tests/cases/compiler/interfacedeclWithIndexerErrors.ts @@ -41,6 +41,13 @@ interface c extends a, b { interface d extends a { } +interface e extends number { +} + +interface f { + prop: typeof string; +} + class c1 implements a { } var instance2 = new c1(); \ No newline at end of file diff --git a/tests/cases/compiler/mappedTypeGenericIndexedAccess.ts b/tests/cases/compiler/mappedTypeGenericIndexedAccess.ts new file mode 100644 index 00000000000..68240b8bc87 --- /dev/null +++ b/tests/cases/compiler/mappedTypeGenericIndexedAccess.ts @@ -0,0 +1,46 @@ +// @strict: true +// @declaration: true + +// Repro from #49242 + +type Types = { + first: { a1: true }; + second: { a2: true }; + third: { a3: true }; +} + +class Test { + entries: { [T in keyof Types]?: Types[T][] }; + + constructor() { + this.entries = {}; + } + + addEntry(name: T, entry: Types[T]) { + if (!this.entries[name]) { + this.entries[name] = []; + } + this.entries[name]?.push(entry); + } +} + +// Repro from #49338 + +type TypesMap = { + [0]: { foo: 'bar'; }; + [1]: { a: 'b'; }; +}; + +type P = { t: T; } & TypesMap[T]; + +type TypeHandlers = { + [T in keyof TypesMap]?: (p: P) => void; +}; + +const typeHandlers: TypeHandlers = { + [0]: (p) => console.log(p.foo), + [1]: (p) => console.log(p.a), +}; + +const onSomeEvent = (p: P) => + typeHandlers[p.t]?.(p); diff --git a/tests/cases/compiler/nodeNextImportModeImplicitIndexResolution2.ts b/tests/cases/compiler/nodeNextImportModeImplicitIndexResolution2.ts new file mode 100644 index 00000000000..12b7844c22b --- /dev/null +++ b/tests/cases/compiler/nodeNextImportModeImplicitIndexResolution2.ts @@ -0,0 +1,37 @@ +// @module: nodenext + +// @Filename: /node_modules/@types/dedent/package.json +{ "name": "@types/dedent", "version": "1.0.0", "main": "" } + +// @Filename: /node_modules/@types/dedent2/package.json +{ "name": "@types/dedent2", "version": "1.0.0", "main": "asdfasdfasdf" } + +// @Filename: /node_modules/@types/dedent3/package.json +{ "name": "@types/dedent3", "version": "1.0.0", "main": "asdfasdfasdf", "exports": null } + +// @Filename: /node_modules/@types/dedent4/package.json +{ "name": "@types/dedent4", "version": "1.0.0", "main": "asdfasdfasdf", "exports": "./asdfasdfasdf" } + +// @Filename: /node_modules/@types/dedent/index.d.ts +export {}; + +// @Filename: /node_modules/@types/dedent2/index.d.ts +export {}; + +// @Filename: /node_modules/@types/dedent3/index.d.ts +export {}; + +// @Filename: /node_modules/@types/dedent4/index.d.ts +export {}; + +// @Filename: /index.mts +import dedent from "dedent"; +import dedent2 from "dedent2"; +import dedent3 from "dedent3"; +import dedent4 from "dedent4"; // Error + +// @Filename: /index.cts +import dedent from "dedent"; +import dedent2 from "dedent2"; +import dedent3 from "dedent3"; +import dedent4 from "dedent4"; // Error diff --git a/tests/cases/compiler/nonNullableTypes1.ts b/tests/cases/compiler/nonNullableTypes1.ts new file mode 100644 index 00000000000..7006c3c1fc6 --- /dev/null +++ b/tests/cases/compiler/nonNullableTypes1.ts @@ -0,0 +1,37 @@ +// @strict: true +// @declaration: true + +function f1(x: T) { + let y = x || "hello"; // NonNullable | string +} + +function error(): never { + throw new Error(); +} + +function f2(x: T) { // NonNullable + return x || error(); +} + +function f3(x: unknown) { + let y = x!; // {} +} + +function f4(obj: T) { + if (obj?.x === "hello") { + obj; // NonNullable + } + if (obj?.x) { + obj; // NonNullable + } + if (typeof obj?.x === "string") { + obj; // NonNullable + } +} + +class A { + x = "hello"; + foo() { + let zz = this?.x; // string + } +} diff --git a/tests/cases/compiler/omittedExpressionForOfLoop.ts b/tests/cases/compiler/omittedExpressionForOfLoop.ts new file mode 100644 index 00000000000..399cd1c1d87 --- /dev/null +++ b/tests/cases/compiler/omittedExpressionForOfLoop.ts @@ -0,0 +1,14 @@ +// @strict: true +// @target: es2015 + +for (const [,] of doesNotExist) { +} + +for (const [,] of undefined) { +} + +for (const [,] of []) { +} + +for (const [] of []) { +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts b/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts new file mode 100644 index 00000000000..c8b02945cad --- /dev/null +++ b/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty8.ts @@ -0,0 +1,32 @@ +// @target: es2019 +type Types = 'boolean' | 'unknown' | 'string'; + +type Properties = { + readonly [key in keyof T]: T[key] extends 'boolean' ? boolean : T[key] extends 'string' ? string : unknown +} + +type AnyCtor

= new (...a: any[]) => P + +declare function classWithProperties(properties: T, klass: AnyCtor

): { + new(): P & Properties; + prototype: P & Properties +}; + +const Base = classWithProperties({ + get x() { return 'boolean' as const }, + y: 'string', +}, class Base { +}); + +class MyClass extends Base { + get x() { + return false; + } + get y() { + return 'hi' + } +} + +const mine = new MyClass(); +const value = mine.x; + diff --git a/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty9.ts b/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty9.ts new file mode 100644 index 00000000000..9dfa1a833b0 --- /dev/null +++ b/tests/cases/conformance/classes/propertyMemberDeclarations/accessorsOverrideProperty9.ts @@ -0,0 +1,49 @@ +// @strict: true +// @target: es2017 +// #41347, based on microsoft/rushstack + +// Mixin utilities +export type Constructor = new (...args: any[]) => T; +export type PropertiesOf = { [K in keyof T]: T[K] }; + +interface IApiItemConstructor extends Constructor, PropertiesOf {} + +// Base class +class ApiItem { + public get members(): ReadonlyArray { + return []; + } +} + +// Normal subclass +class ApiEnumMember extends ApiItem { +} + +// Mixin base class +interface ApiItemContainerMixin extends ApiItem { + readonly members: ReadonlyArray; +} + +function ApiItemContainerMixin( + baseClass: TBaseClass +): TBaseClass & (new (...args: any[]) => ApiItemContainerMixin) { + abstract class MixedClass extends baseClass implements ApiItemContainerMixin { + public constructor(...args: any[]) { + super(...args); + } + + public get members(): ReadonlyArray { + return []; + } + } + + return MixedClass; +} + +// Subclass inheriting from mixin +export class ApiEnum extends ApiItemContainerMixin(ApiItem) { + // This worked prior to TypeScript 4.0: + public get members(): ReadonlyArray { + return []; + } +} diff --git a/tests/cases/conformance/types/literal/templateLiteralTypes4.ts b/tests/cases/conformance/types/literal/templateLiteralTypes4.ts new file mode 100644 index 00000000000..9976c2297d8 --- /dev/null +++ b/tests/cases/conformance/types/literal/templateLiteralTypes4.ts @@ -0,0 +1,307 @@ +// @strict: true +// @target: esnext +// @declaration: true + +// infer from number +type TNumber0 = "100" extends `${infer N extends number}` ? N : never; // 100 +type TNumber1 = "-100" extends `${infer N extends number}` ? N : never; // -100 +type TNumber2 = "1.1" extends `${infer N extends number}` ? N : never; // 1.1 +type TNumber3 = "8e-11" extends `${infer N extends number}` ? N : never; // 8e-11 (0.00000000008) +type TNumber4 = "0x10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +type TNumber5 = "0o10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +type TNumber6 = "0b10" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +type TNumber7 = "10e2" extends `${infer N extends number}` ? N : never; // number (not round-trippable) +type TNumber8 = "abcd" extends `${infer N extends number}` ? N : never; // never + +// infer from bigint +type TBigInt0 = "100" extends `${infer N extends bigint}` ? N : never; // 100n +type TBigInt1 = "-100" extends `${infer N extends bigint}` ? N : never; // -100n +type TBigInt2 = "0x10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) +type TBigInt3 = "0o10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) +type TBigInt4 = "0b10" extends `${infer N extends bigint}` ? N : never; // bigint (not round-trippable) +type TBigInt5 = "1.1" extends `${infer N extends bigint}` ? N : never; // never +type TBigInt6 = "10e2" extends `${infer N extends bigint}` ? N : never; // never +type TBigInt7 = "abcd" extends `${infer N extends bigint}` ? N : never; // never + +// infer from boolean +type TBoolean0 = "true" extends `${infer T extends boolean}` ? T : never; // true +type TBoolean1 = "false" extends `${infer T extends boolean}` ? T : never; // false +type TBoolean2 = "abcd" extends `${infer T extends boolean}` ? T : never; // never + +// infer from null +type TNull0 = "null" extends `${infer T extends null}` ? T : never; // null +type TNull1 = "abcd" extends `${infer T extends null}` ? T : never; // never + +// infer from undefined +type TUndefined0 = "undefined" extends `${infer T extends undefined}` ? T : never; // undefined +type TUndefined1 = "abcd" extends `${infer T extends undefined}` ? T : never; // never + +// infer from literal enums +const enum StringLiteralEnum { Zero = "0", True = "true", False = "false", Undefined = "undefined", Null = "null" } +type TStringLiteralEnum0 = "0" extends `${infer T extends StringLiteralEnum}` ? T : never; // StringLiteralEnum.Zero + +const enum NumberLiteralEnum { Zero, One } +type TNumberLiteralEnum0 = "0" extends `${infer T extends NumberLiteralEnum}` ? T : never; // NumberLiteralEnum.Zero + +// infer from non-literal enums +const enum NonLiteralEnum { Zero = NumberLiteralEnum.Zero, One = NumberLiteralEnum.One } +type TNonLiteralEnum0 = "0" extends `${infer T extends NonLiteralEnum}` ? T : never; // 0 + +// infer using priority: +// string > template-literal > (string-literal | string-literal-enum) > +// number > enum > (number-literal | number-literal-enum) > +// bigint > bigint-literal > +// boolean > (boolean-literal | undefined | null) + +// #region string +// string > string-literal-enum +type PString00 = "0" extends `${infer T extends string | StringLiteralEnum}` ? T : never; // "0" + +// string > number +type PString01 = "0" extends `${infer T extends string | number}` ? T : never; // "0" + +// string > enum +type PString02 = "0" extends `${infer T extends string | NonLiteralEnum}` ? T : never; // "0" + +// string > (number-literal | number-literal-enum) +type PString03 = "0" extends `${infer T extends string | 0}` ? T : never; // "0" +type PString04 = "0" extends `${infer T extends string | NumberLiteralEnum}` ? T : never; // "0" + +// string > bigint +type PString05 = "0" extends `${infer T extends string | bigint}` ? T : never; // "0" + +// string > bigint-literal +type PString06 = "0" extends `${infer T extends string | 0n}` ? T : never; // "0" + +// string > boolean +type PString07 = "true" extends `${infer T extends string | boolean}` ? T : never; // "true" +type PString08 = "false" extends `${infer T extends string | boolean}` ? T : never; // "false" + +// string > (boolean-literal | undefined | null) +type PString09 = "true" extends `${infer T extends string | true}` ? T : never; // "true" +type PString10 = "false" extends `${infer T extends string | false}` ? T : never; // "false" +type PString11 = "undefined" extends `${infer T extends string | undefined}` ? T : never; // "undefined" +type PString12 = "null" extends `${infer T extends string | null}` ? T : never; // "null" +// #endregion string + +// #region template-literal +// template-literal > number +type PTemplate00 = "10" extends `${infer T extends `1${string}` | number}` ? T : never; // "10" + +// template-literal > enum +type PTemplate01 = "10" extends `${infer T extends `1${string}` | NonLiteralEnum}` ? T : never; // "10" + +// template-literal > (number-literal | number-literal-enum) +type PTemplate02 = "10" extends `${infer T extends `1${string}` | 10}` ? T : never; // "10" +type PTemplate03 = "10" extends `${infer T extends `1${string}` | NumberLiteralEnum}` ? T : never; // "10" + +// template-literal > bigint +type PTemplate04 = "10" extends `${infer T extends `1${string}` | bigint}` ? T : never; // "10" + +// template-literal > bigint-literal +type PTemplate05 = "10" extends `${infer T extends `1${string}` | 10n}` ? T : never; // "10" + +// template-literal > boolean +type PTemplate06 = "true" extends `${infer T extends `${string}e` | boolean}` ? T : never; // "true" +type PTemplate07 = "false" extends `${infer T extends `${string}e` | boolean}` ? T : never; // "false" + +// template-literal > (boolean-literal | undefined | null) +type PTemplate08 = "true" extends `${infer T extends `${"t"}${string}` | true}` ? T : never; // "true" +type PTemplate09 = "false" extends `${infer T extends `${"f"}${string}` | false}` ? T : never; // "false" +type PTemplate10 = "undefined" extends `${infer T extends `${"u"}${string}` | undefined}` ? T : never; // "undefined" +type PTemplate11 = "null" extends `${infer T extends `${"n"}${string}` | null}` ? T : never; // "null" +// #endregion template-literal + +// #region string-literal +// string-literal > number +type PStringLiteral00 = "0" extends `${infer T extends "0" | number}` ? T : never; // "0" + +// string-literal > enum +type PStringLiteral01 = "0" extends `${infer T extends "0" | NonLiteralEnum}` ? T : never; // "0" + +// string-literal > (number-literal | number-literal-enum) +type PStringLiteral02 = "0" extends `${infer T extends "0" | 0}` ? T : never; // "0" +type PStringLiteral03 = "0" extends `${infer T extends "0" | NumberLiteralEnum}` ? T : never; // "0" + +// string-literal > bigint +type PStringLiteral04 = "0" extends `${infer T extends "0" | bigint}` ? T : never; // "0" + +// string-literal > bigint-literal +type PStringLiteral05 = "0" extends `${infer T extends "0" | 0n}` ? T : never; // "0" + +// string-literal > boolean +type PStringLiteral06 = "true" extends `${infer T extends "true" | "false" | boolean}` ? T : never; // "true" +type PStringLiteral07 = "false" extends `${infer T extends "true" | "false" | boolean}` ? T : never; // "false" + +// string-literal > (boolean-literal | undefined | null) +type PStringLiteral08 = "true" extends `${infer T extends "true" | true}` ? T : never; // "true" +type PStringLiteral09 = "false" extends `${infer T extends "false" | false}` ? T : never; // "false" +type PStringLiteral10 = "undefined" extends `${infer T extends "undefined" | undefined}` ? T : never; // "undefined" +type PStringLiteral11 = "null" extends `${infer T extends "null" | null}` ? T : never; // "null" +// #endregion string-literal + +// #region string-literal-enum +// string-literal-enum > number +type PStringLiteralEnum00 = "0" extends `${infer T extends StringLiteralEnum | number}` ? T : never; // StringLiteralEnum.Zero + +// string-literal-enum > enum +type PStringLiteralEnum01 = "0" extends `${infer T extends StringLiteralEnum | NonLiteralEnum}` ? T : never; // StringLiteralEnum.Zero + +// string-literal-enum > (number-literal | number-literal-enum) +type PStringLiteralEnum02 = "0" extends `${infer T extends StringLiteralEnum | 0}` ? T : never; // StringLiteralEnum.Zero +type PStringLiteralEnum03 = "0" extends `${infer T extends StringLiteralEnum | NumberLiteralEnum}` ? T : never; // StringLiteralEnum.Zero + +// string-literal-enum > bigint +type PStringLiteralEnum04 = "0" extends `${infer T extends StringLiteralEnum | bigint}` ? T : never; // StringLiteralEnum.Zero + +// string-literal-enum > bigint-literal +type PStringLiteralEnum05 = "0" extends `${infer T extends StringLiteralEnum | 0n}` ? T : never; // StringLiteralEnum.Zero + +// string-literal-enum > boolean +type PStringLiteralEnum06 = "true" extends `${infer T extends StringLiteralEnum | boolean}` ? T : never; // StringLiteralEnum.True +type PStringLiteralEnum07 = "false" extends `${infer T extends StringLiteralEnum | boolean}` ? T : never; // StringLiteralEnum.False + +// string-literal-enum > (boolean-literal | undefined | null) +type PStringLiteralEnum08 = "true" extends `${infer T extends StringLiteralEnum | true}` ? T : never; // StringLiteralEnum.True +type PStringLiteralEnum09 = "false" extends `${infer T extends StringLiteralEnum | false}` ? T : never; // StringLiteralEnum.False +type PStringLiteralEnum10 = "undefined" extends `${infer T extends StringLiteralEnum | undefined}` ? T : never; // StringLiteralEnum.Undefined +type PStringLiteralEnum11 = "null" extends `${infer T extends StringLiteralEnum | null}` ? T : never; // StringLiteralEnum.Null +// #endregion string-literal-enum + +// #region number +// number > enum +type PNumber0 = "0" extends `${infer T extends number | NonLiteralEnum}` ? T : never; // 0 + +// number > number-literal-enum +type PNumber1 = "0" extends `${infer T extends number | NumberLiteralEnum}` ? T : never; // 0 + +// number > bigint +type PNumber2 = "0" extends `${infer T extends number | bigint}` ? T : never; // 0 + +// number > bigint-literal +type PNumber3 = "0" extends `${infer T extends number | 0n}` ? T : never; // 0 +// #endregion number + +// #region enum +// enum > number-literal-enum +type PEnum0 = "0" extends `${infer T extends NonLiteralEnum | NumberLiteralEnum}` ? T : never; // 0 + +// enum > bigint +type PEnum1 = "0" extends `${infer T extends NonLiteralEnum | bigint}` ? T : never; // 0 + +// enum > bigint-literal +type PEnum2 = "0" extends `${infer T extends NonLiteralEnum | 0n}` ? T : never; // 0 +// #endregion enum + +// #region number-literal +// number-literal > bigint +type PNumberLiteral0 = "0" extends `${infer T extends 0 | bigint}` ? T : never; // 0 + +// number-literal > bigint-literal +type PNumberLiteral1 = "0" extends `${infer T extends 0 | 0n}` ? T : never; // 0 +// #endregion number-literal + +// #region number-literal-enum +// number-literal-enum > bigint +type PNumberLiteralEnum0 = "0" extends `${infer T extends NumberLiteralEnum | bigint}` ? T : never; // NumberLiteralEnum.Zero + +// number-literal-enum > bigint-literal +type PNumberLiteralEnum1 = "0" extends `${infer T extends NumberLiteralEnum | 0n}` ? T : never; // NumberLiteralEnum.Zero +// #endregion number-literal-enum + +// non-matchable constituents are excluded +type PExclude0 = "0" extends `${infer T extends "1" | number}` ? T : never; // 0 +type PExclude1 = "0" extends `${infer T extends `1${string}` | number}` ? T : never; // 0 +type PExclude2 = "0" extends `${infer T extends 1 | bigint}` ? T : never; // 0n +type PExclude3 = "0" extends `${infer T extends NumberLiteralEnum.One | bigint}` ? T : never; // 0n +type PExclude4 = "100000000000000000000000" extends `${infer T extends number | bigint}` ? T : never; // 100000000000000000000000n + +// infer to prefix from string +type TPrefix0 = "100" extends `${infer T extends number}${string}` ? T : never; // 1 +type TPrefix1 = "trueabc" extends `${infer T extends boolean}${string}` ? T : never; // boolean (T only receives 't', not the whole string) +type TPrefix2 = `100:${string}` extends `${infer T extends number}:${string}` ? T : never; // 100 (T receives '100' because it scans until ':') + +// can use union w/multiple branches to extract each possibility +type ExtractPrimitives = + | T + | (T extends `${infer U extends number}` ? U : never) + | (T extends `${infer U extends bigint}` ? U : never) + | (T extends `${infer U extends boolean | null | undefined}` ? U : never) + ; + +type TExtract0 = ExtractPrimitives<"100">; // "100" | 100 | 100n +type TExtract1 = ExtractPrimitives<"1.1">; // "1.1" | 1.1 +type TExtract2 = ExtractPrimitives<"true">; // "true" | true + + + +// example use case (based on old TypedObjects proposal): + +// Use constrained `infer` in template literal to get ordinal indices as numbers: +type IndexFor = S extends `${infer N extends number}` ? N : never; +type IndicesOf = IndexFor>; // ordinal indices as number literals + +interface FieldDefinition { + readonly name: string; + readonly type: "i8" | "i16" | "i32" | "i64" | "u8" | "u16" | "u32" | "u64" | "f32" | "f64"; +} + +type FieldType = + T extends "i8" | "i16" | "i32" | "u8" | "u16" | "u32" | "f32" | "f64" ? number : + T extends "f32" | "f64" ? bigint : + never; + +// Generates named members like `{ x: number, y: bigint }` from `[{ name: "x", type: "i32" }, { name: "y", type: "i64" }]` +type TypedObjectNamedMembers = { + [P in TDef[number]["name"]]: FieldType["type"]>; +}; + +// Generates ordinal members like `{ 0: number, 1: bigint }` from `[{ name: "x", type: "i32" }, { name: "y", type: "i64" }]` +type TypedObjectOrdinalMembers = { + [I in Extract]: FieldType["type"]>; +}; + +// Default members +interface TypedObjectMembers { + // get/set a field by name + get(key: K): FieldType["type"]>; + set(key: K, value: FieldType["type"]>): void; + + // get/set a field by index + getIndex>(index: I): FieldType["type"]>; + setIndex>(index: I, value: FieldType["type"]>): void; +} + +type TypedObject = + & TypedObjectMembers + & TypedObjectNamedMembers + & TypedObjectOrdinalMembers; + +// NOTE: type would normally be created from something like `const Point = TypedObject([...])` from which we would infer the type +type Point = TypedObject<[ + { name: "x", type: "f64" }, + { name: "y", type: "f64" }, +]>; + +declare const p: Point; +p.getIndex(0); // ok, 0 is a valid index +p.getIndex(1); // ok, 1 is a valid index +p.getIndex(2); // error, 2 is not a valid index + +p.setIndex(0, 0); // ok, 0 is a valid index +p.setIndex(1, 0); // ok, 1 is a valid index +p.setIndex(2, 3); // error, 2 is not a valid index + +// function inference +declare function f1(s: `**${T}**`): T; +f1("**123**"); // "123" + +declare function f2(s: `**${T}**`): T; +f2("**123**"); // 123 + +declare function f3(s: `**${T}**`): T; +f3("**123**"); // 123n + +declare function f4(s: `**${T}**`): T; +f4("**true**"); // true | "true" +f4("**false**"); // false | "false" diff --git a/tests/cases/conformance/types/unknown/unknownControlFlow.ts b/tests/cases/conformance/types/unknown/unknownControlFlow.ts new file mode 100644 index 00000000000..92a0f279e5e --- /dev/null +++ b/tests/cases/conformance/types/unknown/unknownControlFlow.ts @@ -0,0 +1,262 @@ +// @strict: true +// @declaration: true + +type T01 = {} & string; // string +type T02 = {} & 'a'; // 'a' +type T03 = {} & object; // object +type T04 = {} & { x: number }; // { x: number } +type T05 = {} & null; // never +type T06 = {} & undefined; // never +type T07 = undefined & void; // undefined + +type T10 = string & {}; // Specially preserved +type T11 = number & {}; // Specially preserved +type T12 = bigint & {}; // Specially preserved + +type ThisNode = {}; +type ThatNode = {}; +type ThisOrThatNode = ThisNode | ThatNode; + +function f01(u: unknown) { + let x1: {} = u; // Error + let x2: {} | null | undefined = u; + let x3: {} | { x: string } | null | undefined = u; + let x4: ThisOrThatNode | null | undefined = u; +} + +function f10(x: unknown) { + if (x) { + x; // {} + } + else { + x; // unknown + } + if (!x) { + x; // unknown + } + else { + x; // {} + } +} + +function f11(x: T) { + if (x) { + x; // T & {} + } + else { + x; // T + } + if (!x) { + x; // T + } + else { + x; // T & {} + } +} + +function f12(x: T) { + if (x) { + x; // T + } + else { + x; // T + } +} + +function f20(x: unknown) { + if (x !== undefined) { + x; // {} | null + } + else { + x; // undefined + } + if (x !== null) { + x; // {} | undefined + } + else { + x; // null + } + if (x !== undefined && x !== null) { + x; // {} + } + else { + x; // null | undefined + } + if (x != undefined) { + x; // {} + } + else { + x; // null | undefined + } + if (x != null) { + x; // {} + } + else { + x; // null | undefined + } +} + +function f21(x: T) { + if (x !== undefined) { + x; // T & ({} | null) + } + else { + x; // T + } + if (x !== null) { + x; // T & ({} | undefined) + } + else { + x; // T + } + if (x !== undefined && x !== null) { + x; // T & {} + } + else { + x; // T + } + if (x != undefined) { + x; // T & {} + } + else { + x; // T + } + if (x != null) { + x; // T & {} + } + else { + x; // T + } +} + +function f22(x: T) { + if (x !== undefined) { + x; // T & {} + } + else { + x; // T + } + if (x !== null) { + x; // T + } + else { + x; // T + } + if (x !== undefined && x !== null) { + x; // T & {} + } + else { + x; // T + } + if (x != undefined) { + x; // T & {} + } + else { + x; // T + } + if (x != null) { + x; // T & {} + } + else { + x; // T + } +} + +function f23(x: T | undefined | null) { + if (x !== undefined) { + x; // T & {} | null + } + if (x !== null) { + x; // T & {} | undefined + } + if (x != undefined) { + x; // T & {} + } + if (x != null) { + x; // T & {} + } +} + +function f30(x: {}) { + if (typeof x === "object") { + x; // object + } +} + +function f31(x: T) { + if (typeof x === "object") { + x; // T & object | T & null + } + if (x && typeof x === "object") { + x; // T & object + } + if (typeof x === "object" && x) { + x; // T & object + } +} + +function f32(x: T) { + if (typeof x === "object") { + x; // T & object + } +} + +function possiblyNull(x: T) { + return !!true ? x : null; // T | null +} + +function possiblyUndefined(x: T) { + return !!true ? x : undefined; // T | undefined +} + +function possiblyNullOrUndefined(x: T) { + return possiblyUndefined(possiblyNull(x)); // T | null | undefined +} + +function ensureNotNull(x: T) { + if (x === null) throw Error(); + return x; // T & ({} | undefined) +} + +function ensureNotUndefined(x: T) { + if (x === undefined) throw Error(); + return x; // T & ({} | null) +} + +function ensureNotNullOrUndefined(x: T) { + return ensureNotUndefined(ensureNotNull(x)); // T & {} +} + +function f40(a: string | undefined, b: number | null | undefined) { + let a1 = ensureNotNullOrUndefined(a); // string + let b1 = ensureNotNullOrUndefined(b); // number +} + +type QQ = NonNullable>>; + +function f41(a: T) { + let a1 = ensureNotUndefined(ensureNotNull(a)); // T & {} + let a2 = ensureNotNull(ensureNotUndefined(a)); // T & {} + let a3 = ensureNotNull(ensureNotNull(a)); // T & {} | T & undefined + let a4 = ensureNotUndefined(ensureNotUndefined(a)); // T & {} | T & null + let a5 = ensureNotNullOrUndefined(ensureNotNullOrUndefined(a)); // T & {} + let a6 = ensureNotNull(possiblyNullOrUndefined(a)); // T & {} | undefined + let a7 = ensureNotUndefined(possiblyNullOrUndefined(a)); // T & {} | null + let a8 = ensureNotNull(possiblyUndefined(a)); // T & {} | undefined + let a9 = ensureNotUndefined(possiblyNull(a)); // T & {} | null +} + +// Repro from #48468 + +function deepEquals(a: T, b: T): boolean { + if (typeof a !== 'object' || typeof b !== 'object' || !a || !b) { + return false; + } + if (Array.isArray(a) || Array.isArray(b)) { + return false; + } + if (Object.keys(a).length !== Object.keys(b).length) { // Error here + return false; + } + return true; +} diff --git a/tests/cases/fourslash/completionPreferredSuggestions1.ts b/tests/cases/fourslash/completionPreferredSuggestions1.ts new file mode 100644 index 00000000000..6b9430b4f47 --- /dev/null +++ b/tests/cases/fourslash/completionPreferredSuggestions1.ts @@ -0,0 +1,20 @@ +/// + +////declare let v1: string & {} | "a" | "b" | "c"; +////v1 = "/*1*/"; +////declare let v2: number & {} | 0 | 1 | 2; +////v2 = /*2*/; +////declare let v3: string & Record | "a" | "b" | "c"; +////v3 = "/*3*/"; +////type LiteralUnion1 = T | U & {}; +////type LiteralUnion2 = T | U & Record; +////declare let v4: LiteralUnion1<"a" | "b" | "c", string>; +////v4 = "/*4*/"; +////declare let v5: LiteralUnion2<"a" | "b" | "c", string>; +////v5 = "/*5*/"; + +verify.completions({ marker: "1", includes: ["a", "b", "c"] }); +verify.completions({ marker: "2", includes: ["0", "1", "2"], isNewIdentifierLocation: true }); +verify.completions({ marker: "3", includes: ["a", "b", "c"] }); +verify.completions({ marker: "4", excludes: ["a", "b", "c"] }); +verify.completions({ marker: "5", includes: ["a", "b", "c"] }); diff --git a/tests/cases/fourslash/genericsFormattingMultiline.ts b/tests/cases/fourslash/genericsFormattingMultiline.ts new file mode 100644 index 00000000000..8ee8b09a07d --- /dev/null +++ b/tests/cases/fourslash/genericsFormattingMultiline.ts @@ -0,0 +1,140 @@ +/// + +//// +//// class Foo < +//// T1 extends unknown, +//// T2 +//// > { +//// public method < +//// T3, +//// > (a: T1, b: Array < +//// string +//// > ): Map < +//// T1 , +//// Array < T3 > +//// > { throw new Error(); } +//// } +//// +//// interface IFoo< +//// T, +//// > { +//// new < T +//// > ( a: T); +//// op?< +//// T, +//// M +//// > (a: T, b : M ); +//// < +//// T, +//// >(x: T): T; +//// } +//// +//// type foo< +//// T +//// > = Foo < +//// number, Array < number > > ; +//// +//// function bar < +//// T, U extends T +//// > () { +//// return class < +//// T2, +//// > { +//// } +//// } +//// +//// bar< +//// string, +//// "s" +//// > (); +//// +//// declare const func: < +//// T extends number[], +//// > (x: T) => new < +//// U +//// > () => U; +//// +//// class A < T > extends bar < +//// T,number +//// >( ) < T +//// > { +//// } +//// +//// function s(x: TemplateStringsArray, ...args: any[]) { return x.join(); } +//// +//// const t = s< +//// number , +//// string[] & ArrayLike +//// >`abc${1}def` ; +//// + + +format.document(); + +verify.currentFileContentIs(` +class Foo< + T1 extends unknown, + T2 +> { + public method< + T3, + >(a: T1, b: Array< + string + >): Map< + T1, + Array + > { throw new Error(); } +} + +interface IFoo< + T, +> { + new (a: T); + op?< + T, + M + >(a: T, b: M); + < + T, + >(x: T): T; +} + +type foo< + T +> = Foo< + number, Array>; + +function bar< + T, U extends T +>() { + return class < + T2, + > { + } +} + +bar< + string, + "s" +>(); + +declare const func: < + T extends number[], +> (x: T) => new < + U +> () => U; + +class A extends bar< + T, number +>() { +} + +function s(x: TemplateStringsArray, ...args: any[]) { return x.join(); } + +const t = s< + number, + string[] & ArrayLike +>\`abc\${1}def\`; +`); diff --git a/tests/cases/fourslash/inlayHintsShouldWork68.ts b/tests/cases/fourslash/inlayHintsShouldWork68.ts new file mode 100644 index 00000000000..819041f4ab3 --- /dev/null +++ b/tests/cases/fourslash/inlayHintsShouldWork68.ts @@ -0,0 +1,25 @@ +/// + +////const foo = (a = 1) => class { } +//// +////const C1 = class extends foo(/*1*/1) { } +////class C2 extends foo(/*2*/1) { } + +const markers = test.markers(); + +verify.getInlayHints([ + { + text: 'a:', + position: markers[0].position, + kind: ts.InlayHintKind.Parameter, + whitespaceAfter: true + }, + { + text: 'a:', + position: markers[1].position, + kind: ts.InlayHintKind.Parameter, + whitespaceAfter: true + }, +], undefined, { + includeInlayParameterNameHints: "literals" +});