diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 43297244e1ad5..8310a32d591c8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4069,6 +4069,8 @@ namespace ts { return undefined!; // TODO: GH#18217 } + type = getReducedType(type); + if (type.flags & TypeFlags.Any) { context.approximateLength += 3; return createKeywordTypeNode(SyntaxKind.AnyKeyword); @@ -7133,6 +7135,7 @@ namespace ts { let type: Type | undefined; if (pattern.kind === SyntaxKind.ObjectBindingPattern) { if (declaration.dotDotDotToken) { + parentType = getReducedType(parentType); if (parentType.flags & TypeFlags.Unknown || !isValidSpreadType(parentType)) { error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); return errorType; @@ -8010,13 +8013,17 @@ namespace ts { } function getTypeOfSymbol(symbol: Symbol): Type { - if (getCheckFlags(symbol) & CheckFlags.DeferredType) { + const checkFlags = getCheckFlags(symbol); + if (checkFlags & CheckFlags.DeferredType) { return getTypeOfSymbolWithDeferredType(symbol); } - if (getCheckFlags(symbol) & CheckFlags.Instantiated) { + if (checkFlags & CheckFlags.Instantiated) { return getTypeOfInstantiatedSymbol(symbol); } - if (getCheckFlags(symbol) & CheckFlags.ReverseMapped) { + if (checkFlags & CheckFlags.Mapped) { + return getTypeOfMappedSymbol(symbol as MappedSymbol); + } + if (checkFlags & CheckFlags.ReverseMapped) { return getTypeOfReverseMappedSymbol(symbol as ReverseMappedSymbol); } if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { @@ -8297,7 +8304,7 @@ namespace ts { error(baseTypeNode.expression, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments); return type.resolvedBaseTypes = emptyArray; } - baseType = getReturnTypeOfSignature(constructors[0]); + baseType = getReducedType(getReturnTypeOfSignature(constructors[0])); } if (baseType === errorType) { @@ -8344,8 +8351,8 @@ namespace ts { } // TODO: Given that we allow type parmeters here now, is this `!isGenericMappedType(type)` check really needed? // There's no reason a `T` should be allowed while a `Readonly` should not. - return !!(type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.Any)) && !isGenericMappedType(type) || - !!(type.flags & TypeFlags.Intersection) && every((type).types, isValidBaseType); + return !!(type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.Any) && !isGenericMappedType(type) || + type.flags & TypeFlags.Intersection && every((type).types, isValidBaseType)); } function resolveBaseTypesOfInterface(type: InterfaceType): void { @@ -8353,7 +8360,7 @@ namespace ts { for (const declaration of type.symbol.declarations) { if (declaration.kind === SyntaxKind.InterfaceDeclaration && getInterfaceBaseTypeNodes(declaration)) { for (const node of getInterfaceBaseTypeNodes(declaration)!) { - const baseType = getTypeFromTypeNode(node); + const baseType = getReducedType(getTypeFromTypeNode(node)); if (baseType !== errorType) { if (isValidBaseType(baseType)) { if (type !== baseType && !hasBaseType(baseType, type)) { @@ -9587,7 +9594,6 @@ namespace ts { // mapped type is itself an instantiated type, combine the iteration mapper with the // instantiation mapper. const templateMapper = combineTypeMappers(type.mapper, createTypeMapper([typeParameter], [t])); - const propType = instantiateType(templateType, templateMapper); // If the current iteration type constituent is a string literal type, create a property. // Otherwise, for type string create a string index signature. if (isTypeUsableAsPropertyName(t)) { @@ -9597,13 +9603,11 @@ namespace ts { !(templateModifiers & MappedTypeModifiers.ExcludeOptional) && modifiersProp && modifiersProp.flags & SymbolFlags.Optional); const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly || !(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp && isReadonlySymbol(modifiersProp)); - const prop = createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName, isReadonly ? CheckFlags.Readonly : 0); - // When creating an optional property in strictNullChecks mode, if 'undefined' isn't assignable to the - // type, we include 'undefined' in the type. Similarly, when creating a non-optional property in strictNullChecks - // mode, if the underlying property is optional we remove 'undefined' from the type. - prop.type = strictNullChecks && isOptional && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) ? getOptionalType(propType) : - strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) : - propType; + const stripOptional = strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional; + const prop = createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName, + CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0)); + prop.mappedType = type; + prop.mapper = templateMapper; if (modifiersProp) { prop.syntheticOrigin = modifiersProp; prop.declarations = modifiersProp.declarations; @@ -9611,14 +9615,39 @@ namespace ts { prop.nameType = t; members.set(propName, prop); } - else if (t.flags & (TypeFlags.Any | TypeFlags.String)) { - stringIndexInfo = createIndexInfo(propType, !!(templateModifiers & MappedTypeModifiers.IncludeReadonly)); + else if (t.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.Enum)) { + const propType = instantiateType(templateType, templateMapper); + if (t.flags & (TypeFlags.Any | TypeFlags.String)) { + stringIndexInfo = createIndexInfo(propType, !!(templateModifiers & MappedTypeModifiers.IncludeReadonly)); + } + else { + numberIndexInfo = createIndexInfo(numberIndexInfo ? getUnionType([numberIndexInfo.type, propType]) : propType, + !!(templateModifiers & MappedTypeModifiers.IncludeReadonly)); + } } - else if (t.flags & (TypeFlags.Number | TypeFlags.Enum)) { - numberIndexInfo = createIndexInfo(numberIndexInfo ? getUnionType([numberIndexInfo.type, propType]) : propType, - !!(templateModifiers & MappedTypeModifiers.IncludeReadonly)); + } + } + + function getTypeOfMappedSymbol(symbol: MappedSymbol) { + if (!symbol.type) { + if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { + return errorType; + } + const templateType = getTemplateTypeFromMappedType(symbol.mappedType.target || symbol.mappedType); + const propType = instantiateType(templateType, symbol.mapper); + // When creating an optional property in strictNullChecks mode, if 'undefined' isn't assignable to the + // type, we include 'undefined' in the type. Similarly, when creating a non-optional property in strictNullChecks + // mode, if the underlying property is optional we remove 'undefined' from the type. + let type = strictNullChecks && symbol.flags & SymbolFlags.Optional && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) ? getOptionalType(propType) : + symbol.checkFlags & CheckFlags.StripOptional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) : + propType; + if (!popTypeResolution()) { + error(currentNode, Diagnostics.Type_of_property_0_circularly_references_itself_in_mapped_type_1, symbolToString(symbol), typeToString(symbol.mappedType)); + type = errorType; } + symbol.type = type; } + return symbol.type; } function getTypeParameterFromMappedType(type: MappedType) { @@ -9768,7 +9797,7 @@ namespace ts { } function getPropertiesOfType(type: Type): Symbol[] { - type = getApparentType(type); + type = getApparentType(getReducedType(type)); return type.flags & TypeFlags.UnionOrIntersection ? getPropertiesOfUnionOrIntersectionType(type) : getPropertiesOfObjectType(type); @@ -10109,7 +10138,7 @@ namespace ts { /** * For a type parameter, return the base constraint of the type parameter. For the string, number, * boolean, and symbol primitive types, return the corresponding object types. Otherwise return the - * type itself. Note that the apparent type of a union type is the union type itself. + * type itself. */ function getApparentType(type: Type): Type { const t = type.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(type) || unknownType : type; @@ -10137,7 +10166,7 @@ namespace ts { let checkFlags = 0; for (const current of containingType.types) { const type = getApparentType(current); - if (type !== errorType) { + if (!(type === errorType || type.flags & TypeFlags.Never)) { const prop = getPropertyOfType(type, name); const modifiers = prop ? getDeclarationModifierFlagsFromSymbol(prop) : 0; if (prop && !(modifiers & excludeModifiers)) { @@ -10208,6 +10237,9 @@ namespace ts { if (isLiteralType(type)) { checkFlags |= CheckFlags.HasLiteralType; } + if (type.flags & TypeFlags.Never) { + checkFlags |= CheckFlags.HasNeverType; + } propTypes.push(type); } addRange(propTypes, indexTypes); @@ -10259,6 +10291,44 @@ namespace ts { return property && !(getCheckFlags(property) & CheckFlags.ReadPartial) ? property : undefined; } + /** + * Return the reduced form of the given type. For a union type, it is a union of the normalized constituent types. + * For an intersection of types containing one or more mututally exclusive discriminant properties, it is 'never'. + * For all other types, it is simply the type itself. Discriminant properties are considered mutually exclusive when + * no constituent property has type 'never', but the intersection of the constituent property types is 'never'. + */ + function getReducedType(type: Type): Type { + if (type.flags & TypeFlags.Union && (type).objectFlags & ObjectFlags.ContainsIntersections) { + return (type).resolvedReducedType || ((type).resolvedReducedType = getReducedUnionType(type)); + } + else if (type.flags & TypeFlags.Intersection) { + if (!((type).objectFlags & ObjectFlags.IsNeverIntersectionComputed)) { + (type).objectFlags |= ObjectFlags.IsNeverIntersectionComputed | + (some(getPropertiesOfUnionOrIntersectionType(type), isDiscriminantWithNeverType) ? ObjectFlags.IsNeverIntersection : 0); + } + return (type).objectFlags & ObjectFlags.IsNeverIntersection ? neverType : type; + } + return type; + } + + function getReducedUnionType(unionType: UnionType) { + const reducedTypes = sameMap(unionType.types, getReducedType); + if (reducedTypes === unionType.types) { + return unionType; + } + const reduced = getUnionType(reducedTypes); + if (reduced.flags & TypeFlags.Union) { + (reduced).resolvedReducedType = reduced; + } + return reduced; + } + + function isDiscriminantWithNeverType(prop: Symbol) { + return !(prop.flags & SymbolFlags.Optional) && + (getCheckFlags(prop) & (CheckFlags.Discriminant | CheckFlags.HasNeverType)) === CheckFlags.Discriminant && + !!(getTypeOfSymbol(prop).flags & TypeFlags.Never); + } + /** * Return the symbol for the property with the given name in the given type. Creates synthetic union properties when * necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from @@ -10268,7 +10338,7 @@ namespace ts { * @param name a name of property to look up in a given type */ function getPropertyOfType(type: Type, name: __String): Symbol | undefined { - type = getApparentType(type); + type = getApparentType(getReducedType(type)); if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type); const symbol = resolved.members.get(name); @@ -10306,7 +10376,7 @@ namespace ts { * maps primitive types and type parameters are to their apparent types. */ function getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[] { - return getSignaturesOfStructuredType(getApparentType(type), kind); + return getSignaturesOfStructuredType(getApparentType(getReducedType(type)), kind); } function getIndexInfoOfStructuredType(type: Type, kind: IndexKind): IndexInfo | undefined { @@ -10324,13 +10394,13 @@ namespace ts { // Return the indexing info of the given kind in the given type. Creates synthetic union index types when necessary and // maps primitive types and type parameters are to their apparent types. function getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo | undefined { - return getIndexInfoOfStructuredType(getApparentType(type), kind); + return getIndexInfoOfStructuredType(getApparentType(getReducedType(type)), kind); } // Return the index type of the given kind in the given type. Creates synthetic union index types when necessary and // maps primitive types and type parameters are to their apparent types. function getIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined { - return getIndexTypeOfStructuredType(getApparentType(type), kind); + return getIndexTypeOfStructuredType(getApparentType(getReducedType(type)), kind); } function getImplicitIndexTypeOfType(type: Type, kind: IndexKind): Type | undefined { @@ -11900,7 +11970,9 @@ namespace ts { neverType; } } - return getUnionTypeFromSortedList(typeSet, includes & TypeFlags.NotPrimitiveUnion ? 0 : ObjectFlags.PrimitiveUnion, aliasSymbol, aliasTypeArguments); + const objectFlags = (includes & TypeFlags.NotPrimitiveUnion ? 0 : ObjectFlags.PrimitiveUnion) | + (includes & TypeFlags.Intersection ? ObjectFlags.ContainsIntersections : 0); + return getUnionTypeFromSortedList(typeSet, objectFlags, aliasSymbol, aliasTypeArguments); } function getUnionTypePredicate(signatures: readonly Signature[]): TypePredicate | undefined { @@ -12268,6 +12340,7 @@ namespace ts { } function getIndexType(type: Type, stringsOnly = keyofStringsOnly, noIndexSignatures?: boolean): Type { + type = getReducedType(type); return type.flags & TypeFlags.Union ? getIntersectionType(map((type).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) : type.flags & TypeFlags.Intersection ? getUnionType(map((type).types, t => getIndexType(t, stringsOnly, noIndexSignatures))) : maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(type, stringsOnly) : @@ -12684,7 +12757,7 @@ namespace ts { // In the following we resolve T[K] to the type of the property in T selected by K. // We treat boolean as different from other unions to improve errors; // skipping straight to getPropertyTypeForIndexType gives errors with 'boolean' instead of 'true'. - const apparentObjectType = getApparentType(objectType); + const apparentObjectType = getApparentType(getReducedType(objectType)); if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Boolean)) { const propTypes: Type[] = []; let wasMissingProp = false; @@ -13665,7 +13738,7 @@ namespace ts { if (typeVariable) { const mappedTypeVariable = instantiateType(typeVariable, mapper); if (typeVariable !== mappedTypeVariable) { - return mapType(mappedTypeVariable, t => { + return mapType(getReducedType(mappedTypeVariable), t => { if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && t !== errorType) { const replacementMapper = createReplacementMapper(typeVariable, t, mapper); return isArrayType(t) ? instantiateMappedArrayType(t, type, replacementMapper) : @@ -14807,7 +14880,8 @@ namespace ts { } } else { - if (!(source.flags === target.flags && source.flags & TypeFlags.Substructure)) return false; + if (!(source.flags & TypeFlags.UnionOrIntersection) && !(target.flags & TypeFlags.UnionOrIntersection) && + source.flags !== target.flags && !(source.flags & TypeFlags.Substructure)) return false; } if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) { const related = relation.get(getRelationKey(source, target, IntersectionState.None, relation)); @@ -14826,15 +14900,16 @@ namespace ts { } function getNormalizedType(type: Type, writing: boolean): Type { - do { + while (true) { const t = isFreshLiteralType(type) ? (type).regularType : getObjectFlags(type) & ObjectFlags.Reference && (type).node ? createTypeReference((type).target, getTypeArguments(type)) : + type.flags & TypeFlags.UnionOrIntersection ? getReducedType(type) : type.flags & TypeFlags.Substitution ? writing ? (type).typeVariable : (type).substitute : type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) : type; if (t === type) break; type = t; - } while (true); + } return type; } @@ -18122,6 +18197,7 @@ namespace ts { } } else { + source = getReducedType(source); if (!(priority & InferencePriority.NoConstraints && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable))) { const apparentSource = getApparentType(source); // getApparentType can return _any_ type, since an indexed access or conditional may simplify to any other type. @@ -22523,7 +22599,7 @@ namespace ts { hasComputedStringProperty = false; hasComputedNumberProperty = false; } - const type = checkExpression(memberDecl.expression); + const type = getReducedType(checkExpression(memberDecl.expression)); if (!isValidSpreadType(type)) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return errorType; @@ -22731,7 +22807,7 @@ namespace ts { spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false); attributesTable = createSymbolTable(); } - const exprType = checkExpressionCached(attributeDecl.expression, checkMode); + const exprType = getReducedType(checkExpressionCached(attributeDecl.expression, checkMode)); if (isTypeAny(exprType)) { hasSpreadAnyType = true; } @@ -32606,7 +32682,7 @@ namespace ts { } checkTypeReferenceNode(typeRefNode); if (produceDiagnostics) { - const t = getTypeFromTypeNode(typeRefNode); + const t = getReducedType(getTypeFromTypeNode(typeRefNode)); if (t !== errorType) { if (isValidBaseType(t)) { const genericDiag = t.symbol && t.symbol.flags & SymbolFlags.Class ? diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 4ee407ce1c1e9..0063311aec667 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2361,6 +2361,10 @@ "category": "Error", "code": 2614 }, + "Type of property '{0}' circularly references itself in mapped type '{1}'.": { + "category": "Error", + "code": 2615 + }, "Cannot augment module '{0}' with value exports because it resolves to a non-module entity.": { "category": "Error", diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 2824307ccd46f..969aafad3e2f4 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1795,9 +1795,7 @@ namespace ts { const target = getTargetOfBindingOrAssignmentElement(bindingElement); if (target && isPropertyName(target)) { - return isComputedPropertyName(target) && isStringOrNumericLiteral(target.expression) - ? target.expression - : target; + return target; } } diff --git a/src/compiler/transformers/classFields.ts b/src/compiler/transformers/classFields.ts index a4c8878fbbcbb..692f353b00e57 100644 --- a/src/compiler/transformers/classFields.ts +++ b/src/compiler/transformers/classFields.ts @@ -976,7 +976,7 @@ namespace ts { ); } - function visitArrayAssignmentTarget(node: AssignmentPattern) { + function visitArrayAssignmentTarget(node: BindingOrAssignmentElement) { const target = getTargetOfBindingOrAssignmentElement(node); if (target && isPrivateIdentifierPropertyAccessExpression(target)) { const wrapped = wrapPrivateIdentifierForDestructuringTarget(target); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 74cd04d767412..c4a5351fec5ee 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4136,6 +4136,9 @@ namespace ts { OptionalParameter = 1 << 14, // Optional parameter RestParameter = 1 << 15, // Rest parameter DeferredType = 1 << 16, // Calculation of the type of this symbol is deferred due to processing costs, should be fetched with `getTypeOfSymbolWithDeferredType` + HasNeverType = 1 << 17, // Synthetic property with at least one never type in constituents + Mapped = 1 << 18, // Property of mapped type + StripOptional = 1 << 19, // Strip optionality in mapped property Synthetic = SyntheticProperty | SyntheticMethod, Discriminant = HasNonUniformType | HasLiteralType, Partial = ReadPartial | WritePartial @@ -4146,6 +4149,12 @@ namespace ts { checkFlags: CheckFlags; } + /* @internal */ + export interface MappedSymbol extends TransientSymbol { + mappedType: MappedType; + mapper: TypeMapper; + } + /* @internal */ export interface ReverseMappedSymbol extends TransientSymbol { propertyType: Type; @@ -4343,16 +4352,16 @@ namespace ts { NotPrimitiveUnion = Any | Unknown | Enum | Void | Never | StructuredOrInstantiable, // The following flags are aggregated during union and intersection type construction /* @internal */ - IncludesMask = Any | Unknown | Primitive | Never | Object | Union | NonPrimitive, + IncludesMask = Any | Unknown | Primitive | Never | Object | Union | Intersection | NonPrimitive, // The following flags are used for different purposes during union and intersection type construction /* @internal */ IncludesStructuredOrInstantiable = TypeParameter, /* @internal */ - IncludesNonWideningType = Intersection, + IncludesNonWideningType = Index, /* @internal */ - IncludesWildcard = Index, + IncludesWildcard = IndexedAccess, /* @internal */ - IncludesEmptyObject = IndexedAccess, + IncludesEmptyObject = Conditional, } export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; @@ -4468,6 +4477,12 @@ namespace ts { CouldContainTypeVariablesComputed = 1 << 26, // CouldContainTypeVariables flag has been computed /* @internal */ CouldContainTypeVariables = 1 << 27, // Type could contain a type variable + /* @internal */ + ContainsIntersections = 1 << 28, // Union contains intersections + /* @internal */ + IsNeverIntersectionComputed = 1 << 28, // IsNeverLike flag has been computed + /* @internal */ + IsNeverIntersection = 1 << 29, // Intersection reduces to never ClassOrInterface = Class | Interface, /* @internal */ RequiresWidening = ContainsWideningType | ContainsObjectOrArrayLiteral, @@ -4589,6 +4604,8 @@ namespace ts { } export interface UnionType extends UnionOrIntersectionType { + /* @internal */ + resolvedReducedType: Type; } export interface IntersectionType extends UnionOrIntersectionType { diff --git a/tests/baselines/reference/discriminatedUnionTypes2.errors.txt b/tests/baselines/reference/discriminatedUnionTypes2.errors.txt index 0cb87c1aa5931..f2ced8d19fa6c 100644 --- a/tests/baselines/reference/discriminatedUnionTypes2.errors.txt +++ b/tests/baselines/reference/discriminatedUnionTypes2.errors.txt @@ -2,10 +2,9 @@ tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(27,30): error TS Object literal may only specify known properties, and 'c' does not exist in type '{ a: null; b: string; }'. tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(32,11): error TS2339: Property 'b' does not exist on type '{ a: 0; b: string; } | { a: T; c: number; }'. Property 'b' does not exist on type '{ a: T; c: number; }'. -tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(132,11): error TS2339: Property 'value' does not exist on type 'never'. -==== tests/cases/conformance/types/union/discriminatedUnionTypes2.ts (3 errors) ==== +==== tests/cases/conformance/types/union/discriminatedUnionTypes2.ts (2 errors) ==== function f10(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) { if (x.kind === false) { x.a; @@ -143,9 +142,7 @@ tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(132,11): error T x.value; // number } else { - x.value; // Error, x is never - ~~~~~ -!!! error TS2339: Property 'value' does not exist on type 'never'. + x.value; // number } } diff --git a/tests/baselines/reference/discriminatedUnionTypes2.js b/tests/baselines/reference/discriminatedUnionTypes2.js index 584678ee7fa53..b94c386b4699e 100644 --- a/tests/baselines/reference/discriminatedUnionTypes2.js +++ b/tests/baselines/reference/discriminatedUnionTypes2.js @@ -130,7 +130,7 @@ function foo1(x: RuntimeValue & { type: 'number' }) { x.value; // number } else { - x.value; // Error, x is never + x.value; // number } } @@ -226,7 +226,7 @@ function foo1(x) { x.value; // number } else { - x.value; // Error, x is never + x.value; // number } } function foo2(x) { diff --git a/tests/baselines/reference/discriminatedUnionTypes2.symbols b/tests/baselines/reference/discriminatedUnionTypes2.symbols index d338561cb535c..747f43ac21e4c 100644 --- a/tests/baselines/reference/discriminatedUnionTypes2.symbols +++ b/tests/baselines/reference/discriminatedUnionTypes2.symbols @@ -317,9 +317,9 @@ function f(problem: abc & (b | c)) { >c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 104, 1)) if (problem.type === 'b') { ->problem.type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 101, 10), Decl(discriminatedUnionTypes2.ts, 105, 10), Decl(discriminatedUnionTypes2.ts, 97, 10), Decl(discriminatedUnionTypes2.ts, 101, 10), Decl(discriminatedUnionTypes2.ts, 97, 10) ... and 5 more) +>problem.type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 101, 10), Decl(discriminatedUnionTypes2.ts, 105, 10)) >problem : Symbol(problem, Decl(discriminatedUnionTypes2.ts, 112, 11)) ->type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 101, 10), Decl(discriminatedUnionTypes2.ts, 105, 10), Decl(discriminatedUnionTypes2.ts, 97, 10), Decl(discriminatedUnionTypes2.ts, 101, 10), Decl(discriminatedUnionTypes2.ts, 97, 10) ... and 5 more) +>type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 101, 10), Decl(discriminatedUnionTypes2.ts, 105, 10)) problem.name; >problem.name : Symbol(name, Decl(discriminatedUnionTypes2.ts, 102, 14)) @@ -356,9 +356,9 @@ function foo1(x: RuntimeValue & { type: 'number' }) { >type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 126, 33)) if (x.type === 'number') { ->x.type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 122, 7), Decl(discriminatedUnionTypes2.ts, 126, 33), Decl(discriminatedUnionTypes2.ts, 123, 7), Decl(discriminatedUnionTypes2.ts, 126, 33), Decl(discriminatedUnionTypes2.ts, 124, 7) ... and 1 more) +>x.type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 122, 7), Decl(discriminatedUnionTypes2.ts, 126, 33)) >x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 126, 14)) ->type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 122, 7), Decl(discriminatedUnionTypes2.ts, 126, 33), Decl(discriminatedUnionTypes2.ts, 123, 7), Decl(discriminatedUnionTypes2.ts, 126, 33), Decl(discriminatedUnionTypes2.ts, 124, 7) ... and 1 more) +>type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 122, 7), Decl(discriminatedUnionTypes2.ts, 126, 33)) x.value; // number >x.value : Symbol(value, Decl(discriminatedUnionTypes2.ts, 122, 23)) @@ -366,8 +366,10 @@ function foo1(x: RuntimeValue & { type: 'number' }) { >value : Symbol(value, Decl(discriminatedUnionTypes2.ts, 122, 23)) } else { - x.value; // Error, x is never + x.value; // number +>x.value : Symbol(value, Decl(discriminatedUnionTypes2.ts, 122, 23)) >x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 126, 14)) +>value : Symbol(value, Decl(discriminatedUnionTypes2.ts, 122, 23)) } } @@ -379,9 +381,9 @@ function foo2(x: RuntimeValue & ({ type: 'number' } | { type: 'string' })) { >type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 135, 55)) if (x.type === 'number') { ->x.type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 122, 7), Decl(discriminatedUnionTypes2.ts, 135, 34), Decl(discriminatedUnionTypes2.ts, 122, 7), Decl(discriminatedUnionTypes2.ts, 135, 55), Decl(discriminatedUnionTypes2.ts, 123, 7) ... and 7 more) +>x.type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 122, 7), Decl(discriminatedUnionTypes2.ts, 135, 34), Decl(discriminatedUnionTypes2.ts, 123, 7), Decl(discriminatedUnionTypes2.ts, 135, 55)) >x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 135, 14)) ->type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 122, 7), Decl(discriminatedUnionTypes2.ts, 135, 34), Decl(discriminatedUnionTypes2.ts, 122, 7), Decl(discriminatedUnionTypes2.ts, 135, 55), Decl(discriminatedUnionTypes2.ts, 123, 7) ... and 7 more) +>type : Symbol(type, Decl(discriminatedUnionTypes2.ts, 122, 7), Decl(discriminatedUnionTypes2.ts, 135, 34), Decl(discriminatedUnionTypes2.ts, 123, 7), Decl(discriminatedUnionTypes2.ts, 135, 55)) x.value; // number >x.value : Symbol(value, Decl(discriminatedUnionTypes2.ts, 122, 23)) diff --git a/tests/baselines/reference/discriminatedUnionTypes2.types b/tests/baselines/reference/discriminatedUnionTypes2.types index 96759a759cb0a..51130779608a6 100644 --- a/tests/baselines/reference/discriminatedUnionTypes2.types +++ b/tests/baselines/reference/discriminatedUnionTypes2.types @@ -323,13 +323,13 @@ type abc = a | b | c; >abc : abc function f(problem: abc & (b | c)) { ->f : (problem: b | c | (a & b) | (a & c) | (b & c) | (c & b)) => void ->problem : b | c | (a & b) | (a & c) | (b & c) | (c & b) +>f : (problem: b | c) => void +>problem : b | c if (problem.type === 'b') { >problem.type === 'b' : boolean >problem.type : "b" | "c" ->problem : b | c | (a & b) | (a & c) | (b & c) | (c & b) +>problem : b | c >type : "b" | "c" >'b' : "b" @@ -362,14 +362,14 @@ type RuntimeValue = >value : boolean function foo1(x: RuntimeValue & { type: 'number' }) { ->foo1 : (x: ({ type: "number"; value: number; } & { type: "number"; }) | ({ type: "string"; value: string; } & { type: "number"; }) | ({ type: "boolean"; value: boolean; } & { type: "number"; })) => void ->x : ({ type: "number"; value: number; } & { type: "number"; }) | ({ type: "string"; value: string; } & { type: "number"; }) | ({ type: "boolean"; value: boolean; } & { type: "number"; }) +>foo1 : (x: { type: "number"; value: number; } & { type: "number"; }) => void +>x : { type: "number"; value: number; } & { type: "number"; } >type : "number" if (x.type === 'number') { >x.type === 'number' : boolean >x.type : "number" ->x : ({ type: "number"; value: number; } & { type: "number"; }) | ({ type: "string"; value: string; } & { type: "number"; }) | ({ type: "boolean"; value: boolean; } & { type: "number"; }) +>x : { type: "number"; value: number; } & { type: "number"; } >type : "number" >'number' : "number" @@ -379,23 +379,23 @@ function foo1(x: RuntimeValue & { type: 'number' }) { >value : number } else { - x.value; // Error, x is never ->x.value : any ->x : never ->value : any + x.value; // number +>x.value : number +>x : { type: "number"; value: number; } & { type: "number"; } +>value : number } } function foo2(x: RuntimeValue & ({ type: 'number' } | { type: 'string' })) { ->foo2 : (x: ({ type: "number"; value: number; } & { type: "number"; }) | ({ type: "number"; value: number; } & { type: "string"; }) | ({ type: "string"; value: string; } & { type: "number"; }) | ({ type: "string"; value: string; } & { type: "string"; }) | ({ type: "boolean"; value: boolean; } & { type: "number"; }) | ({ type: "boolean"; value: boolean; } & { type: "string"; })) => void ->x : ({ type: "number"; value: number; } & { type: "number"; }) | ({ type: "number"; value: number; } & { type: "string"; }) | ({ type: "string"; value: string; } & { type: "number"; }) | ({ type: "string"; value: string; } & { type: "string"; }) | ({ type: "boolean"; value: boolean; } & { type: "number"; }) | ({ type: "boolean"; value: boolean; } & { type: "string"; }) +>foo2 : (x: ({ type: "number"; value: number; } & { type: "number"; }) | ({ type: "string"; value: string; } & { type: "string"; })) => void +>x : ({ type: "number"; value: number; } & { type: "number"; }) | ({ type: "string"; value: string; } & { type: "string"; }) >type : "number" >type : "string" if (x.type === 'number') { >x.type === 'number' : boolean >x.type : "string" | "number" ->x : ({ type: "number"; value: number; } & { type: "number"; }) | ({ type: "number"; value: number; } & { type: "string"; }) | ({ type: "string"; value: string; } & { type: "number"; }) | ({ type: "string"; value: string; } & { type: "string"; }) | ({ type: "boolean"; value: boolean; } & { type: "number"; }) | ({ type: "boolean"; value: boolean; } & { type: "string"; }) +>x : ({ type: "number"; value: number; } & { type: "number"; }) | ({ type: "string"; value: string; } & { type: "string"; }) >type : "string" | "number" >'number' : "number" diff --git a/tests/baselines/reference/intersectionReduction.errors.txt b/tests/baselines/reference/intersectionReduction.errors.txt index 62631cca76b3c..7f979f3aeabe8 100644 --- a/tests/baselines/reference/intersectionReduction.errors.txt +++ b/tests/baselines/reference/intersectionReduction.errors.txt @@ -1,8 +1,9 @@ -tests/cases/conformance/types/intersection/intersectionReduction.ts(40,1): error TS2322: Type 'any' is not assignable to type 'never'. -tests/cases/conformance/types/intersection/intersectionReduction.ts(41,1): error TS2322: Type 'any' is not assignable to type 'never'. +tests/cases/conformance/types/intersection/intersectionReduction.ts(38,4): error TS2339: Property 'kind' does not exist on type 'never'. +tests/cases/conformance/types/intersection/intersectionReduction.ts(80,1): error TS2322: Type 'any' is not assignable to type 'never'. +tests/cases/conformance/types/intersection/intersectionReduction.ts(81,1): error TS2322: Type 'any' is not assignable to type 'never'. -==== tests/cases/conformance/types/intersection/intersectionReduction.ts (2 errors) ==== +==== tests/cases/conformance/types/intersection/intersectionReduction.ts (3 errors) ==== declare const sym1: unique symbol; declare const sym2: unique symbol; @@ -35,6 +36,48 @@ tests/cases/conformance/types/intersection/intersectionReduction.ts(41,1): error type X6 = X | symbol & string; type X7 = X | void & string; + type A = { kind: 'a', foo: string }; + type B = { kind: 'b', foo: number }; + type C = { kind: 'c', foo: number }; + + declare let ab: A & B; + ab.kind; // Error + ~~~~ +!!! error TS2339: Property 'kind' does not exist on type 'never'. + + declare let x: A | (B & C); // A + let a: A = x; + + type AB = A & B; // never + type BC = B & C; // never + + type U1 = Partial; // never + type U2 = Readonly; // never + type U3 = (A & B)['kind']; // never + type U4 = A & B | B & C; // never + type U5 = A | B & C; // A + + type K1 = keyof (A & B); // string | number | symbol + type K2 = keyof A | keyof B; // 'kind' | 'foo' + + type Merge1 = { [P in keyof (T & U)]: P extends keyof T ? T[P] : U[P & keyof U] } + type Merge2 = { [P in keyof T | keyof U]: P extends keyof T ? T[P] : U[P & keyof U] } + + type M1 = { a: 1, b: 2 } & { a: 2, c: 3 }; // never + type M2 = Merge1<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // {} + type M3 = Merge2<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // { a: 1, b: 2, c: 3 } + + type D = { kind: 'd', foo: unknown }; + type E = { kind: 'e', foo: unknown }; + + declare function f10(x: { foo: T }): T; + + declare let a1: A | D; + declare let a2: A | D & E; + + let r1 = f10(a1); // unknown + let r2 = f10(a2); // string + // Repro from #31663 const x1 = { a: 'foo', b: 42 }; @@ -63,4 +106,16 @@ tests/cases/conformance/types/intersection/intersectionReduction.ts(41,1): error t1 = t2; t2 = t1; + + // Repro from #36736 + + const f1 = (t: "a" | ("b" & "c")): "a" => t; + + type Container = { + type: Type; + } + + const f2 = (t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t; + const f3 = (t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t; + const f4 = (t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t; \ No newline at end of file diff --git a/tests/baselines/reference/intersectionReduction.js b/tests/baselines/reference/intersectionReduction.js index f2009cd9cc7e8..c04ce9973bcbe 100644 --- a/tests/baselines/reference/intersectionReduction.js +++ b/tests/baselines/reference/intersectionReduction.js @@ -31,6 +31,46 @@ type X5 = X | number & object; type X6 = X | symbol & string; type X7 = X | void & string; +type A = { kind: 'a', foo: string }; +type B = { kind: 'b', foo: number }; +type C = { kind: 'c', foo: number }; + +declare let ab: A & B; +ab.kind; // Error + +declare let x: A | (B & C); // A +let a: A = x; + +type AB = A & B; // never +type BC = B & C; // never + +type U1 = Partial; // never +type U2 = Readonly; // never +type U3 = (A & B)['kind']; // never +type U4 = A & B | B & C; // never +type U5 = A | B & C; // A + +type K1 = keyof (A & B); // string | number | symbol +type K2 = keyof A | keyof B; // 'kind' | 'foo' + +type Merge1 = { [P in keyof (T & U)]: P extends keyof T ? T[P] : U[P & keyof U] } +type Merge2 = { [P in keyof T | keyof U]: P extends keyof T ? T[P] : U[P & keyof U] } + +type M1 = { a: 1, b: 2 } & { a: 2, c: 3 }; // never +type M2 = Merge1<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // {} +type M3 = Merge2<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // { a: 1, b: 2, c: 3 } + +type D = { kind: 'd', foo: unknown }; +type E = { kind: 'e', foo: unknown }; + +declare function f10(x: { foo: T }): T; + +declare let a1: A | D; +declare let a2: A | D & E; + +let r1 = f10(a1); // unknown +let r2 = f10(a2); // string + // Repro from #31663 const x1 = { a: 'foo', b: 42 }; @@ -55,9 +95,25 @@ s2 = s1; t1 = t2; t2 = t1; + +// Repro from #36736 + +const f1 = (t: "a" | ("b" & "c")): "a" => t; + +type Container = { + type: Type; +} + +const f2 = (t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t; +const f3 = (t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t; +const f4 = (t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t; //// [intersectionReduction.js] +ab.kind; // Error +var a = x; +var r1 = f10(a1); // unknown +var r2 = f10(a2); // string // Repro from #31663 var x1 = { a: 'foo', b: 42 }; var x2 = { a: 'foo', b: true }; @@ -67,3 +123,8 @@ s1 = s2; s2 = s1; t1 = t2; t2 = t1; +// Repro from #36736 +var f1 = function (t) { return t; }; +var f2 = function (t) { return t; }; +var f3 = function (t) { return t; }; +var f4 = function (t) { return t; }; diff --git a/tests/baselines/reference/intersectionReduction.symbols b/tests/baselines/reference/intersectionReduction.symbols index 3e22d2e26965f..2949e87b2c72a 100644 --- a/tests/baselines/reference/intersectionReduction.symbols +++ b/tests/baselines/reference/intersectionReduction.symbols @@ -93,64 +93,283 @@ type X7 = X | void & string; >X7 : Symbol(X7, Decl(intersectionReduction.ts, 29, 30)) >X : Symbol(X, Decl(intersectionReduction.ts, 20, 24)) +type A = { kind: 'a', foo: string }; +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>kind : Symbol(kind, Decl(intersectionReduction.ts, 32, 10)) +>foo : Symbol(foo, Decl(intersectionReduction.ts, 32, 21)) + +type B = { kind: 'b', foo: number }; +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) +>kind : Symbol(kind, Decl(intersectionReduction.ts, 33, 10)) +>foo : Symbol(foo, Decl(intersectionReduction.ts, 33, 21)) + +type C = { kind: 'c', foo: number }; +>C : Symbol(C, Decl(intersectionReduction.ts, 33, 36)) +>kind : Symbol(kind, Decl(intersectionReduction.ts, 34, 10)) +>foo : Symbol(foo, Decl(intersectionReduction.ts, 34, 21)) + +declare let ab: A & B; +>ab : Symbol(ab, Decl(intersectionReduction.ts, 36, 11)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) + +ab.kind; // Error +>ab : Symbol(ab, Decl(intersectionReduction.ts, 36, 11)) + +declare let x: A | (B & C); // A +>x : Symbol(x, Decl(intersectionReduction.ts, 39, 11)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) +>C : Symbol(C, Decl(intersectionReduction.ts, 33, 36)) + +let a: A = x; +>a : Symbol(a, Decl(intersectionReduction.ts, 40, 3)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>x : Symbol(x, Decl(intersectionReduction.ts, 39, 11)) + +type AB = A & B; // never +>AB : Symbol(AB, Decl(intersectionReduction.ts, 40, 13)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) + +type BC = B & C; // never +>BC : Symbol(BC, Decl(intersectionReduction.ts, 42, 16)) +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) +>C : Symbol(C, Decl(intersectionReduction.ts, 33, 36)) + +type U1 = Partial; // never +>U1 : Symbol(U1, Decl(intersectionReduction.ts, 43, 16)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) + +type U2 = Readonly; // never +>U2 : Symbol(U2, Decl(intersectionReduction.ts, 45, 25)) +>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) + +type U3 = (A & B)['kind']; // never +>U3 : Symbol(U3, Decl(intersectionReduction.ts, 46, 26)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) + +type U4 = A & B | B & C; // never +>U4 : Symbol(U4, Decl(intersectionReduction.ts, 47, 26)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) +>C : Symbol(C, Decl(intersectionReduction.ts, 33, 36)) + +type U5 = A | B & C; // A +>U5 : Symbol(U5, Decl(intersectionReduction.ts, 48, 24)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) +>C : Symbol(C, Decl(intersectionReduction.ts, 33, 36)) + +type K1 = keyof (A & B); // string | number | symbol +>K1 : Symbol(K1, Decl(intersectionReduction.ts, 49, 20)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) + +type K2 = keyof A | keyof B; // 'kind' | 'foo' +>K2 : Symbol(K2, Decl(intersectionReduction.ts, 51, 24)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReduction.ts, 32, 36)) + +type Merge1 = { [P in keyof (T & U)]: P extends keyof T ? T[P] : U[P & keyof U] } +>Merge1 : Symbol(Merge1, Decl(intersectionReduction.ts, 52, 28)) +>T : Symbol(T, Decl(intersectionReduction.ts, 54, 12)) +>U : Symbol(U, Decl(intersectionReduction.ts, 54, 14)) +>P : Symbol(P, Decl(intersectionReduction.ts, 54, 23)) +>T : Symbol(T, Decl(intersectionReduction.ts, 54, 12)) +>U : Symbol(U, Decl(intersectionReduction.ts, 54, 14)) +>P : Symbol(P, Decl(intersectionReduction.ts, 54, 23)) +>T : Symbol(T, Decl(intersectionReduction.ts, 54, 12)) +>T : Symbol(T, Decl(intersectionReduction.ts, 54, 12)) +>P : Symbol(P, Decl(intersectionReduction.ts, 54, 23)) +>U : Symbol(U, Decl(intersectionReduction.ts, 54, 14)) +>P : Symbol(P, Decl(intersectionReduction.ts, 54, 23)) +>U : Symbol(U, Decl(intersectionReduction.ts, 54, 14)) + +type Merge2 = { [P in keyof T | keyof U]: P extends keyof T ? T[P] : U[P & keyof U] } +>Merge2 : Symbol(Merge2, Decl(intersectionReduction.ts, 54, 87)) +>T : Symbol(T, Decl(intersectionReduction.ts, 55, 12)) +>U : Symbol(U, Decl(intersectionReduction.ts, 55, 14)) +>P : Symbol(P, Decl(intersectionReduction.ts, 55, 23)) +>T : Symbol(T, Decl(intersectionReduction.ts, 55, 12)) +>U : Symbol(U, Decl(intersectionReduction.ts, 55, 14)) +>P : Symbol(P, Decl(intersectionReduction.ts, 55, 23)) +>T : Symbol(T, Decl(intersectionReduction.ts, 55, 12)) +>T : Symbol(T, Decl(intersectionReduction.ts, 55, 12)) +>P : Symbol(P, Decl(intersectionReduction.ts, 55, 23)) +>U : Symbol(U, Decl(intersectionReduction.ts, 55, 14)) +>P : Symbol(P, Decl(intersectionReduction.ts, 55, 23)) +>U : Symbol(U, Decl(intersectionReduction.ts, 55, 14)) + +type M1 = { a: 1, b: 2 } & { a: 2, c: 3 }; // never +>M1 : Symbol(M1, Decl(intersectionReduction.ts, 55, 91)) +>a : Symbol(a, Decl(intersectionReduction.ts, 57, 11)) +>b : Symbol(b, Decl(intersectionReduction.ts, 57, 17)) +>a : Symbol(a, Decl(intersectionReduction.ts, 57, 28)) +>c : Symbol(c, Decl(intersectionReduction.ts, 57, 34)) + +type M2 = Merge1<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // {} +>M2 : Symbol(M2, Decl(intersectionReduction.ts, 57, 42)) +>Merge1 : Symbol(Merge1, Decl(intersectionReduction.ts, 52, 28)) +>a : Symbol(a, Decl(intersectionReduction.ts, 58, 18)) +>b : Symbol(b, Decl(intersectionReduction.ts, 58, 24)) +>a : Symbol(a, Decl(intersectionReduction.ts, 58, 34)) +>c : Symbol(c, Decl(intersectionReduction.ts, 58, 40)) + +type M3 = Merge2<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // { a: 1, b: 2, c: 3 } +>M3 : Symbol(M3, Decl(intersectionReduction.ts, 58, 49)) +>Merge2 : Symbol(Merge2, Decl(intersectionReduction.ts, 54, 87)) +>a : Symbol(a, Decl(intersectionReduction.ts, 59, 18)) +>b : Symbol(b, Decl(intersectionReduction.ts, 59, 24)) +>a : Symbol(a, Decl(intersectionReduction.ts, 59, 34)) +>c : Symbol(c, Decl(intersectionReduction.ts, 59, 40)) + +type D = { kind: 'd', foo: unknown }; +>D : Symbol(D, Decl(intersectionReduction.ts, 59, 49)) +>kind : Symbol(kind, Decl(intersectionReduction.ts, 61, 10)) +>foo : Symbol(foo, Decl(intersectionReduction.ts, 61, 21)) + +type E = { kind: 'e', foo: unknown }; +>E : Symbol(E, Decl(intersectionReduction.ts, 61, 37)) +>kind : Symbol(kind, Decl(intersectionReduction.ts, 62, 10)) +>foo : Symbol(foo, Decl(intersectionReduction.ts, 62, 21)) + +declare function f10(x: { foo: T }): T; +>f10 : Symbol(f10, Decl(intersectionReduction.ts, 62, 37)) +>T : Symbol(T, Decl(intersectionReduction.ts, 64, 21)) +>x : Symbol(x, Decl(intersectionReduction.ts, 64, 24)) +>foo : Symbol(foo, Decl(intersectionReduction.ts, 64, 28)) +>T : Symbol(T, Decl(intersectionReduction.ts, 64, 21)) +>T : Symbol(T, Decl(intersectionReduction.ts, 64, 21)) + +declare let a1: A | D; +>a1 : Symbol(a1, Decl(intersectionReduction.ts, 66, 11)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>D : Symbol(D, Decl(intersectionReduction.ts, 59, 49)) + +declare let a2: A | D & E; +>a2 : Symbol(a2, Decl(intersectionReduction.ts, 67, 11)) +>A : Symbol(A, Decl(intersectionReduction.ts, 30, 28)) +>D : Symbol(D, Decl(intersectionReduction.ts, 59, 49)) +>E : Symbol(E, Decl(intersectionReduction.ts, 61, 37)) + +let r1 = f10(a1); // unknown +>r1 : Symbol(r1, Decl(intersectionReduction.ts, 69, 3)) +>f10 : Symbol(f10, Decl(intersectionReduction.ts, 62, 37)) +>a1 : Symbol(a1, Decl(intersectionReduction.ts, 66, 11)) + +let r2 = f10(a2); // string +>r2 : Symbol(r2, Decl(intersectionReduction.ts, 70, 3)) +>f10 : Symbol(f10, Decl(intersectionReduction.ts, 62, 37)) +>a2 : Symbol(a2, Decl(intersectionReduction.ts, 67, 11)) + // Repro from #31663 const x1 = { a: 'foo', b: 42 }; ->x1 : Symbol(x1, Decl(intersectionReduction.ts, 34, 5)) ->a : Symbol(a, Decl(intersectionReduction.ts, 34, 12)) ->b : Symbol(b, Decl(intersectionReduction.ts, 34, 22)) +>x1 : Symbol(x1, Decl(intersectionReduction.ts, 74, 5)) +>a : Symbol(a, Decl(intersectionReduction.ts, 74, 12)) +>b : Symbol(b, Decl(intersectionReduction.ts, 74, 22)) const x2 = { a: 'foo', b: true }; ->x2 : Symbol(x2, Decl(intersectionReduction.ts, 35, 5)) ->a : Symbol(a, Decl(intersectionReduction.ts, 35, 12)) ->b : Symbol(b, Decl(intersectionReduction.ts, 35, 22)) +>x2 : Symbol(x2, Decl(intersectionReduction.ts, 75, 5)) +>a : Symbol(a, Decl(intersectionReduction.ts, 75, 12)) +>b : Symbol(b, Decl(intersectionReduction.ts, 75, 22)) declare let k: 'a' | 'b'; ->k : Symbol(k, Decl(intersectionReduction.ts, 37, 11)) +>k : Symbol(k, Decl(intersectionReduction.ts, 77, 11)) x1[k] = 'bar' as any; // Error ->x1 : Symbol(x1, Decl(intersectionReduction.ts, 34, 5)) ->k : Symbol(k, Decl(intersectionReduction.ts, 37, 11)) +>x1 : Symbol(x1, Decl(intersectionReduction.ts, 74, 5)) +>k : Symbol(k, Decl(intersectionReduction.ts, 77, 11)) x2[k] = 'bar' as any; // Error ->x2 : Symbol(x2, Decl(intersectionReduction.ts, 35, 5)) ->k : Symbol(k, Decl(intersectionReduction.ts, 37, 11)) +>x2 : Symbol(x2, Decl(intersectionReduction.ts, 75, 5)) +>k : Symbol(k, Decl(intersectionReduction.ts, 77, 11)) const enum Tag1 {} ->Tag1 : Symbol(Tag1, Decl(intersectionReduction.ts, 40, 21)) +>Tag1 : Symbol(Tag1, Decl(intersectionReduction.ts, 80, 21)) const enum Tag2 {} ->Tag2 : Symbol(Tag2, Decl(intersectionReduction.ts, 42, 18)) +>Tag2 : Symbol(Tag2, Decl(intersectionReduction.ts, 82, 18)) declare let s1: string & Tag1; ->s1 : Symbol(s1, Decl(intersectionReduction.ts, 45, 11)) ->Tag1 : Symbol(Tag1, Decl(intersectionReduction.ts, 40, 21)) +>s1 : Symbol(s1, Decl(intersectionReduction.ts, 85, 11)) +>Tag1 : Symbol(Tag1, Decl(intersectionReduction.ts, 80, 21)) declare let s2: string & Tag2; ->s2 : Symbol(s2, Decl(intersectionReduction.ts, 46, 11)) ->Tag2 : Symbol(Tag2, Decl(intersectionReduction.ts, 42, 18)) +>s2 : Symbol(s2, Decl(intersectionReduction.ts, 86, 11)) +>Tag2 : Symbol(Tag2, Decl(intersectionReduction.ts, 82, 18)) declare let t1: string & Tag1 | undefined; ->t1 : Symbol(t1, Decl(intersectionReduction.ts, 48, 11)) ->Tag1 : Symbol(Tag1, Decl(intersectionReduction.ts, 40, 21)) +>t1 : Symbol(t1, Decl(intersectionReduction.ts, 88, 11)) +>Tag1 : Symbol(Tag1, Decl(intersectionReduction.ts, 80, 21)) declare let t2: string & Tag2 | undefined; ->t2 : Symbol(t2, Decl(intersectionReduction.ts, 49, 11)) ->Tag2 : Symbol(Tag2, Decl(intersectionReduction.ts, 42, 18)) +>t2 : Symbol(t2, Decl(intersectionReduction.ts, 89, 11)) +>Tag2 : Symbol(Tag2, Decl(intersectionReduction.ts, 82, 18)) s1 = s2; ->s1 : Symbol(s1, Decl(intersectionReduction.ts, 45, 11)) ->s2 : Symbol(s2, Decl(intersectionReduction.ts, 46, 11)) +>s1 : Symbol(s1, Decl(intersectionReduction.ts, 85, 11)) +>s2 : Symbol(s2, Decl(intersectionReduction.ts, 86, 11)) s2 = s1; ->s2 : Symbol(s2, Decl(intersectionReduction.ts, 46, 11)) ->s1 : Symbol(s1, Decl(intersectionReduction.ts, 45, 11)) +>s2 : Symbol(s2, Decl(intersectionReduction.ts, 86, 11)) +>s1 : Symbol(s1, Decl(intersectionReduction.ts, 85, 11)) t1 = t2; ->t1 : Symbol(t1, Decl(intersectionReduction.ts, 48, 11)) ->t2 : Symbol(t2, Decl(intersectionReduction.ts, 49, 11)) +>t1 : Symbol(t1, Decl(intersectionReduction.ts, 88, 11)) +>t2 : Symbol(t2, Decl(intersectionReduction.ts, 89, 11)) t2 = t1; ->t2 : Symbol(t2, Decl(intersectionReduction.ts, 49, 11)) ->t1 : Symbol(t1, Decl(intersectionReduction.ts, 48, 11)) +>t2 : Symbol(t2, Decl(intersectionReduction.ts, 89, 11)) +>t1 : Symbol(t1, Decl(intersectionReduction.ts, 88, 11)) + +// Repro from #36736 + +const f1 = (t: "a" | ("b" & "c")): "a" => t; +>f1 : Symbol(f1, Decl(intersectionReduction.ts, 99, 5)) +>t : Symbol(t, Decl(intersectionReduction.ts, 99, 12)) +>t : Symbol(t, Decl(intersectionReduction.ts, 99, 12)) + +type Container = { +>Container : Symbol(Container, Decl(intersectionReduction.ts, 99, 44)) +>Type : Symbol(Type, Decl(intersectionReduction.ts, 101, 15)) + + type: Type; +>type : Symbol(type, Decl(intersectionReduction.ts, 101, 39)) +>Type : Symbol(Type, Decl(intersectionReduction.ts, 101, 15)) +} + +const f2 = (t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t; +>f2 : Symbol(f2, Decl(intersectionReduction.ts, 105, 5)) +>t : Symbol(t, Decl(intersectionReduction.ts, 105, 12)) +>Container : Symbol(Container, Decl(intersectionReduction.ts, 99, 44)) +>Container : Symbol(Container, Decl(intersectionReduction.ts, 99, 44)) +>Container : Symbol(Container, Decl(intersectionReduction.ts, 99, 44)) +>Container : Symbol(Container, Decl(intersectionReduction.ts, 99, 44)) +>t : Symbol(t, Decl(intersectionReduction.ts, 105, 12)) + +const f3 = (t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t; +>f3 : Symbol(f3, Decl(intersectionReduction.ts, 106, 5)) +>t : Symbol(t, Decl(intersectionReduction.ts, 106, 12)) +>Container : Symbol(Container, Decl(intersectionReduction.ts, 99, 44)) +>Container : Symbol(Container, Decl(intersectionReduction.ts, 99, 44)) +>dataB : Symbol(dataB, Decl(intersectionReduction.ts, 106, 51)) +>Container : Symbol(Container, Decl(intersectionReduction.ts, 99, 44)) +>Container : Symbol(Container, Decl(intersectionReduction.ts, 99, 44)) +>t : Symbol(t, Decl(intersectionReduction.ts, 106, 12)) + +const f4 = (t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t; +>f4 : Symbol(f4, Decl(intersectionReduction.ts, 107, 5)) +>t : Symbol(t, Decl(intersectionReduction.ts, 107, 12)) +>Container : Symbol(Container, Decl(intersectionReduction.ts, 99, 44)) +>dataB : Symbol(dataB, Decl(intersectionReduction.ts, 107, 43)) +>Container : Symbol(Container, Decl(intersectionReduction.ts, 99, 44)) +>t : Symbol(t, Decl(intersectionReduction.ts, 107, 12)) diff --git a/tests/baselines/reference/intersectionReduction.types b/tests/baselines/reference/intersectionReduction.types index 9dfeea5c0e508..7bb24e68351ad 100644 --- a/tests/baselines/reference/intersectionReduction.types +++ b/tests/baselines/reference/intersectionReduction.types @@ -88,6 +88,123 @@ type X6 = X | symbol & string; type X7 = X | void & string; >X7 : X +type A = { kind: 'a', foo: string }; +>A : A +>kind : "a" +>foo : string + +type B = { kind: 'b', foo: number }; +>B : B +>kind : "b" +>foo : number + +type C = { kind: 'c', foo: number }; +>C : C +>kind : "c" +>foo : number + +declare let ab: A & B; +>ab : never + +ab.kind; // Error +>ab.kind : any +>ab : never +>kind : any + +declare let x: A | (B & C); // A +>x : A + +let a: A = x; +>a : A +>x : A + +type AB = A & B; // never +>AB : never + +type BC = B & C; // never +>BC : never + +type U1 = Partial; // never +>U1 : never + +type U2 = Readonly; // never +>U2 : never + +type U3 = (A & B)['kind']; // never +>U3 : never + +type U4 = A & B | B & C; // never +>U4 : never + +type U5 = A | B & C; // A +>U5 : A + +type K1 = keyof (A & B); // string | number | symbol +>K1 : string | number | symbol + +type K2 = keyof A | keyof B; // 'kind' | 'foo' +>K2 : "kind" | "foo" + +type Merge1 = { [P in keyof (T & U)]: P extends keyof T ? T[P] : U[P & keyof U] } +>Merge1 : Merge1 + +type Merge2 = { [P in keyof T | keyof U]: P extends keyof T ? T[P] : U[P & keyof U] } +>Merge2 : Merge2 + +type M1 = { a: 1, b: 2 } & { a: 2, c: 3 }; // never +>M1 : never +>a : 1 +>b : 2 +>a : 2 +>c : 3 + +type M2 = Merge1<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // {} +>M2 : Merge1<{ a: 1; b: 2; }, { a: 2; c: 3; }> +>a : 1 +>b : 2 +>a : 2 +>c : 3 + +type M3 = Merge2<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // { a: 1, b: 2, c: 3 } +>M3 : Merge2<{ a: 1; b: 2; }, { a: 2; c: 3; }> +>a : 1 +>b : 2 +>a : 2 +>c : 3 + +type D = { kind: 'd', foo: unknown }; +>D : D +>kind : "d" +>foo : unknown + +type E = { kind: 'e', foo: unknown }; +>E : E +>kind : "e" +>foo : unknown + +declare function f10(x: { foo: T }): T; +>f10 : (x: { foo: T; }) => T +>x : { foo: T; } +>foo : T + +declare let a1: A | D; +>a1 : A | D + +declare let a2: A | D & E; +>a2 : A + +let r1 = f10(a1); // unknown +>r1 : unknown +>f10(a1) : unknown +>f10 : (x: { foo: T; }) => T +>a1 : A | D + +let r2 = f10(a2); // string +>r2 : string +>f10(a2) : string +>f10 : (x: { foo: T; }) => T +>a2 : A + // Repro from #31663 const x1 = { a: 'foo', b: 42 }; @@ -163,3 +280,38 @@ t2 = t1; >t2 : undefined >t1 : undefined +// Repro from #36736 + +const f1 = (t: "a" | ("b" & "c")): "a" => t; +>f1 : (t: "a") => "a" +>(t: "a" | ("b" & "c")): "a" => t : (t: "a") => "a" +>t : "a" +>t : "a" + +type Container = { +>Container : Container + + type: Type; +>type : Type +} + +const f2 = (t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t; +>f2 : (t: Container<"a">) => Container<"a"> +>(t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t : (t: Container<"a">) => Container<"a"> +>t : Container<"a"> +>t : Container<"a"> + +const f3 = (t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t; +>f3 : (t: Container<"a">) => Container<"a"> +>(t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t : (t: Container<"a">) => Container<"a"> +>t : Container<"a"> +>dataB : boolean +>t : Container<"a"> + +const f4 = (t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t; +>f4 : (t: number) => number +>(t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t : (t: number) => number +>t : number +>dataB : boolean +>t : number + diff --git a/tests/baselines/reference/intersectionReductionStrict.errors.txt b/tests/baselines/reference/intersectionReductionStrict.errors.txt index bf174ce04ef60..fe3e67fdc2ea7 100644 --- a/tests/baselines/reference/intersectionReductionStrict.errors.txt +++ b/tests/baselines/reference/intersectionReductionStrict.errors.txt @@ -1,8 +1,9 @@ -tests/cases/conformance/types/intersection/intersectionReductionStrict.ts(40,1): error TS2322: Type 'any' is not assignable to type 'never'. -tests/cases/conformance/types/intersection/intersectionReductionStrict.ts(41,1): error TS2322: Type 'any' is not assignable to type 'never'. +tests/cases/conformance/types/intersection/intersectionReductionStrict.ts(38,4): error TS2339: Property 'kind' does not exist on type 'never'. +tests/cases/conformance/types/intersection/intersectionReductionStrict.ts(69,1): error TS2322: Type 'any' is not assignable to type 'never'. +tests/cases/conformance/types/intersection/intersectionReductionStrict.ts(70,1): error TS2322: Type 'any' is not assignable to type 'never'. -==== tests/cases/conformance/types/intersection/intersectionReductionStrict.ts (2 errors) ==== +==== tests/cases/conformance/types/intersection/intersectionReductionStrict.ts (3 errors) ==== declare const sym1: unique symbol; declare const sym2: unique symbol; @@ -35,6 +36,37 @@ tests/cases/conformance/types/intersection/intersectionReductionStrict.ts(41,1): type X6 = X | symbol & string; type X7 = X | void & string; + type A = { kind: 'a', foo: string }; + type B = { kind: 'b', foo: number }; + type C = { kind: 'c', foo: number }; + + declare let ab: A & B; + ab.kind; // Error + ~~~~ +!!! error TS2339: Property 'kind' does not exist on type 'never'. + + declare let x: A | (B & C); // A + let a: A = x; + + type AB = A & B; // never + type BC = B & C; // never + + type U1 = Partial; // never + type U2 = Readonly; // never + type U3 = (A & B)['kind']; // never + type U4 = A & B | B & C; // never + type U5 = A | B & C; // A + + type K1 = keyof (A & B); // string | number | symbol + type K2 = keyof A | keyof B; // 'kind' | 'foo' + + type Merge1 = { [P in keyof (T & U)]: P extends keyof T ? T[P] : U[P & keyof U] } + type Merge2 = { [P in keyof T | keyof U]: P extends keyof T ? T[P] : U[P & keyof U] } + + type M1 = { a: 1, b: 2 } & { a: 2, c: 3 }; // never + type M2 = Merge1<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // {} + type M3 = Merge2<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // { a: 1, b: 2, c: 3 } + // Repro from #31663 const x1 = { a: 'foo', b: 42 }; @@ -63,4 +95,16 @@ tests/cases/conformance/types/intersection/intersectionReductionStrict.ts(41,1): t1 = t2; t2 = t1; + + // Repro from #36736 + + const f1 = (t: "a" | ("b" & "c")): "a" => t; + + type Container = { + type: Type; + } + + const f2 = (t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t; + const f3 = (t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t; + const f4 = (t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t; \ No newline at end of file diff --git a/tests/baselines/reference/intersectionReductionStrict.js b/tests/baselines/reference/intersectionReductionStrict.js index 32845471a06a2..f6618967bbc54 100644 --- a/tests/baselines/reference/intersectionReductionStrict.js +++ b/tests/baselines/reference/intersectionReductionStrict.js @@ -31,6 +31,35 @@ type X5 = X | number & object; type X6 = X | symbol & string; type X7 = X | void & string; +type A = { kind: 'a', foo: string }; +type B = { kind: 'b', foo: number }; +type C = { kind: 'c', foo: number }; + +declare let ab: A & B; +ab.kind; // Error + +declare let x: A | (B & C); // A +let a: A = x; + +type AB = A & B; // never +type BC = B & C; // never + +type U1 = Partial; // never +type U2 = Readonly; // never +type U3 = (A & B)['kind']; // never +type U4 = A & B | B & C; // never +type U5 = A | B & C; // A + +type K1 = keyof (A & B); // string | number | symbol +type K2 = keyof A | keyof B; // 'kind' | 'foo' + +type Merge1 = { [P in keyof (T & U)]: P extends keyof T ? T[P] : U[P & keyof U] } +type Merge2 = { [P in keyof T | keyof U]: P extends keyof T ? T[P] : U[P & keyof U] } + +type M1 = { a: 1, b: 2 } & { a: 2, c: 3 }; // never +type M2 = Merge1<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // {} +type M3 = Merge2<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // { a: 1, b: 2, c: 3 } + // Repro from #31663 const x1 = { a: 'foo', b: 42 }; @@ -55,10 +84,24 @@ s2 = s1; t1 = t2; t2 = t1; + +// Repro from #36736 + +const f1 = (t: "a" | ("b" & "c")): "a" => t; + +type Container = { + type: Type; +} + +const f2 = (t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t; +const f3 = (t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t; +const f4 = (t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t; //// [intersectionReductionStrict.js] "use strict"; +ab.kind; // Error +var a = x; // Repro from #31663 var x1 = { a: 'foo', b: 42 }; var x2 = { a: 'foo', b: true }; @@ -68,3 +111,8 @@ s1 = s2; s2 = s1; t1 = t2; t2 = t1; +// Repro from #36736 +var f1 = function (t) { return t; }; +var f2 = function (t) { return t; }; +var f3 = function (t) { return t; }; +var f4 = function (t) { return t; }; diff --git a/tests/baselines/reference/intersectionReductionStrict.symbols b/tests/baselines/reference/intersectionReductionStrict.symbols index 6e9d7e03a8e04..f2851fb643c2a 100644 --- a/tests/baselines/reference/intersectionReductionStrict.symbols +++ b/tests/baselines/reference/intersectionReductionStrict.symbols @@ -93,64 +93,244 @@ type X7 = X | void & string; >X7 : Symbol(X7, Decl(intersectionReductionStrict.ts, 29, 30)) >X : Symbol(X, Decl(intersectionReductionStrict.ts, 20, 24)) +type A = { kind: 'a', foo: string }; +>A : Symbol(A, Decl(intersectionReductionStrict.ts, 30, 28)) +>kind : Symbol(kind, Decl(intersectionReductionStrict.ts, 32, 10)) +>foo : Symbol(foo, Decl(intersectionReductionStrict.ts, 32, 21)) + +type B = { kind: 'b', foo: number }; +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) +>kind : Symbol(kind, Decl(intersectionReductionStrict.ts, 33, 10)) +>foo : Symbol(foo, Decl(intersectionReductionStrict.ts, 33, 21)) + +type C = { kind: 'c', foo: number }; +>C : Symbol(C, Decl(intersectionReductionStrict.ts, 33, 36)) +>kind : Symbol(kind, Decl(intersectionReductionStrict.ts, 34, 10)) +>foo : Symbol(foo, Decl(intersectionReductionStrict.ts, 34, 21)) + +declare let ab: A & B; +>ab : Symbol(ab, Decl(intersectionReductionStrict.ts, 36, 11)) +>A : Symbol(A, Decl(intersectionReductionStrict.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) + +ab.kind; // Error +>ab : Symbol(ab, Decl(intersectionReductionStrict.ts, 36, 11)) + +declare let x: A | (B & C); // A +>x : Symbol(x, Decl(intersectionReductionStrict.ts, 39, 11)) +>A : Symbol(A, Decl(intersectionReductionStrict.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) +>C : Symbol(C, Decl(intersectionReductionStrict.ts, 33, 36)) + +let a: A = x; +>a : Symbol(a, Decl(intersectionReductionStrict.ts, 40, 3)) +>A : Symbol(A, Decl(intersectionReductionStrict.ts, 30, 28)) +>x : Symbol(x, Decl(intersectionReductionStrict.ts, 39, 11)) + +type AB = A & B; // never +>AB : Symbol(AB, Decl(intersectionReductionStrict.ts, 40, 13)) +>A : Symbol(A, Decl(intersectionReductionStrict.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) + +type BC = B & C; // never +>BC : Symbol(BC, Decl(intersectionReductionStrict.ts, 42, 16)) +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) +>C : Symbol(C, Decl(intersectionReductionStrict.ts, 33, 36)) + +type U1 = Partial; // never +>U1 : Symbol(U1, Decl(intersectionReductionStrict.ts, 43, 16)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(intersectionReductionStrict.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) + +type U2 = Readonly; // never +>U2 : Symbol(U2, Decl(intersectionReductionStrict.ts, 45, 25)) +>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(intersectionReductionStrict.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) + +type U3 = (A & B)['kind']; // never +>U3 : Symbol(U3, Decl(intersectionReductionStrict.ts, 46, 26)) +>A : Symbol(A, Decl(intersectionReductionStrict.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) + +type U4 = A & B | B & C; // never +>U4 : Symbol(U4, Decl(intersectionReductionStrict.ts, 47, 26)) +>A : Symbol(A, Decl(intersectionReductionStrict.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) +>C : Symbol(C, Decl(intersectionReductionStrict.ts, 33, 36)) + +type U5 = A | B & C; // A +>U5 : Symbol(U5, Decl(intersectionReductionStrict.ts, 48, 24)) +>A : Symbol(A, Decl(intersectionReductionStrict.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) +>C : Symbol(C, Decl(intersectionReductionStrict.ts, 33, 36)) + +type K1 = keyof (A & B); // string | number | symbol +>K1 : Symbol(K1, Decl(intersectionReductionStrict.ts, 49, 20)) +>A : Symbol(A, Decl(intersectionReductionStrict.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) + +type K2 = keyof A | keyof B; // 'kind' | 'foo' +>K2 : Symbol(K2, Decl(intersectionReductionStrict.ts, 51, 24)) +>A : Symbol(A, Decl(intersectionReductionStrict.ts, 30, 28)) +>B : Symbol(B, Decl(intersectionReductionStrict.ts, 32, 36)) + +type Merge1 = { [P in keyof (T & U)]: P extends keyof T ? T[P] : U[P & keyof U] } +>Merge1 : Symbol(Merge1, Decl(intersectionReductionStrict.ts, 52, 28)) +>T : Symbol(T, Decl(intersectionReductionStrict.ts, 54, 12)) +>U : Symbol(U, Decl(intersectionReductionStrict.ts, 54, 14)) +>P : Symbol(P, Decl(intersectionReductionStrict.ts, 54, 23)) +>T : Symbol(T, Decl(intersectionReductionStrict.ts, 54, 12)) +>U : Symbol(U, Decl(intersectionReductionStrict.ts, 54, 14)) +>P : Symbol(P, Decl(intersectionReductionStrict.ts, 54, 23)) +>T : Symbol(T, Decl(intersectionReductionStrict.ts, 54, 12)) +>T : Symbol(T, Decl(intersectionReductionStrict.ts, 54, 12)) +>P : Symbol(P, Decl(intersectionReductionStrict.ts, 54, 23)) +>U : Symbol(U, Decl(intersectionReductionStrict.ts, 54, 14)) +>P : Symbol(P, Decl(intersectionReductionStrict.ts, 54, 23)) +>U : Symbol(U, Decl(intersectionReductionStrict.ts, 54, 14)) + +type Merge2 = { [P in keyof T | keyof U]: P extends keyof T ? T[P] : U[P & keyof U] } +>Merge2 : Symbol(Merge2, Decl(intersectionReductionStrict.ts, 54, 87)) +>T : Symbol(T, Decl(intersectionReductionStrict.ts, 55, 12)) +>U : Symbol(U, Decl(intersectionReductionStrict.ts, 55, 14)) +>P : Symbol(P, Decl(intersectionReductionStrict.ts, 55, 23)) +>T : Symbol(T, Decl(intersectionReductionStrict.ts, 55, 12)) +>U : Symbol(U, Decl(intersectionReductionStrict.ts, 55, 14)) +>P : Symbol(P, Decl(intersectionReductionStrict.ts, 55, 23)) +>T : Symbol(T, Decl(intersectionReductionStrict.ts, 55, 12)) +>T : Symbol(T, Decl(intersectionReductionStrict.ts, 55, 12)) +>P : Symbol(P, Decl(intersectionReductionStrict.ts, 55, 23)) +>U : Symbol(U, Decl(intersectionReductionStrict.ts, 55, 14)) +>P : Symbol(P, Decl(intersectionReductionStrict.ts, 55, 23)) +>U : Symbol(U, Decl(intersectionReductionStrict.ts, 55, 14)) + +type M1 = { a: 1, b: 2 } & { a: 2, c: 3 }; // never +>M1 : Symbol(M1, Decl(intersectionReductionStrict.ts, 55, 91)) +>a : Symbol(a, Decl(intersectionReductionStrict.ts, 57, 11)) +>b : Symbol(b, Decl(intersectionReductionStrict.ts, 57, 17)) +>a : Symbol(a, Decl(intersectionReductionStrict.ts, 57, 28)) +>c : Symbol(c, Decl(intersectionReductionStrict.ts, 57, 34)) + +type M2 = Merge1<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // {} +>M2 : Symbol(M2, Decl(intersectionReductionStrict.ts, 57, 42)) +>Merge1 : Symbol(Merge1, Decl(intersectionReductionStrict.ts, 52, 28)) +>a : Symbol(a, Decl(intersectionReductionStrict.ts, 58, 18)) +>b : Symbol(b, Decl(intersectionReductionStrict.ts, 58, 24)) +>a : Symbol(a, Decl(intersectionReductionStrict.ts, 58, 34)) +>c : Symbol(c, Decl(intersectionReductionStrict.ts, 58, 40)) + +type M3 = Merge2<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // { a: 1, b: 2, c: 3 } +>M3 : Symbol(M3, Decl(intersectionReductionStrict.ts, 58, 49)) +>Merge2 : Symbol(Merge2, Decl(intersectionReductionStrict.ts, 54, 87)) +>a : Symbol(a, Decl(intersectionReductionStrict.ts, 59, 18)) +>b : Symbol(b, Decl(intersectionReductionStrict.ts, 59, 24)) +>a : Symbol(a, Decl(intersectionReductionStrict.ts, 59, 34)) +>c : Symbol(c, Decl(intersectionReductionStrict.ts, 59, 40)) + // Repro from #31663 const x1 = { a: 'foo', b: 42 }; ->x1 : Symbol(x1, Decl(intersectionReductionStrict.ts, 34, 5)) ->a : Symbol(a, Decl(intersectionReductionStrict.ts, 34, 12)) ->b : Symbol(b, Decl(intersectionReductionStrict.ts, 34, 22)) +>x1 : Symbol(x1, Decl(intersectionReductionStrict.ts, 63, 5)) +>a : Symbol(a, Decl(intersectionReductionStrict.ts, 63, 12)) +>b : Symbol(b, Decl(intersectionReductionStrict.ts, 63, 22)) const x2 = { a: 'foo', b: true }; ->x2 : Symbol(x2, Decl(intersectionReductionStrict.ts, 35, 5)) ->a : Symbol(a, Decl(intersectionReductionStrict.ts, 35, 12)) ->b : Symbol(b, Decl(intersectionReductionStrict.ts, 35, 22)) +>x2 : Symbol(x2, Decl(intersectionReductionStrict.ts, 64, 5)) +>a : Symbol(a, Decl(intersectionReductionStrict.ts, 64, 12)) +>b : Symbol(b, Decl(intersectionReductionStrict.ts, 64, 22)) declare let k: 'a' | 'b'; ->k : Symbol(k, Decl(intersectionReductionStrict.ts, 37, 11)) +>k : Symbol(k, Decl(intersectionReductionStrict.ts, 66, 11)) x1[k] = 'bar' as any; // Error ->x1 : Symbol(x1, Decl(intersectionReductionStrict.ts, 34, 5)) ->k : Symbol(k, Decl(intersectionReductionStrict.ts, 37, 11)) +>x1 : Symbol(x1, Decl(intersectionReductionStrict.ts, 63, 5)) +>k : Symbol(k, Decl(intersectionReductionStrict.ts, 66, 11)) x2[k] = 'bar' as any; // Error ->x2 : Symbol(x2, Decl(intersectionReductionStrict.ts, 35, 5)) ->k : Symbol(k, Decl(intersectionReductionStrict.ts, 37, 11)) +>x2 : Symbol(x2, Decl(intersectionReductionStrict.ts, 64, 5)) +>k : Symbol(k, Decl(intersectionReductionStrict.ts, 66, 11)) const enum Tag1 {} ->Tag1 : Symbol(Tag1, Decl(intersectionReductionStrict.ts, 40, 21)) +>Tag1 : Symbol(Tag1, Decl(intersectionReductionStrict.ts, 69, 21)) const enum Tag2 {} ->Tag2 : Symbol(Tag2, Decl(intersectionReductionStrict.ts, 42, 18)) +>Tag2 : Symbol(Tag2, Decl(intersectionReductionStrict.ts, 71, 18)) declare let s1: string & Tag1; ->s1 : Symbol(s1, Decl(intersectionReductionStrict.ts, 45, 11)) ->Tag1 : Symbol(Tag1, Decl(intersectionReductionStrict.ts, 40, 21)) +>s1 : Symbol(s1, Decl(intersectionReductionStrict.ts, 74, 11)) +>Tag1 : Symbol(Tag1, Decl(intersectionReductionStrict.ts, 69, 21)) declare let s2: string & Tag2; ->s2 : Symbol(s2, Decl(intersectionReductionStrict.ts, 46, 11)) ->Tag2 : Symbol(Tag2, Decl(intersectionReductionStrict.ts, 42, 18)) +>s2 : Symbol(s2, Decl(intersectionReductionStrict.ts, 75, 11)) +>Tag2 : Symbol(Tag2, Decl(intersectionReductionStrict.ts, 71, 18)) declare let t1: string & Tag1 | undefined; ->t1 : Symbol(t1, Decl(intersectionReductionStrict.ts, 48, 11)) ->Tag1 : Symbol(Tag1, Decl(intersectionReductionStrict.ts, 40, 21)) +>t1 : Symbol(t1, Decl(intersectionReductionStrict.ts, 77, 11)) +>Tag1 : Symbol(Tag1, Decl(intersectionReductionStrict.ts, 69, 21)) declare let t2: string & Tag2 | undefined; ->t2 : Symbol(t2, Decl(intersectionReductionStrict.ts, 49, 11)) ->Tag2 : Symbol(Tag2, Decl(intersectionReductionStrict.ts, 42, 18)) +>t2 : Symbol(t2, Decl(intersectionReductionStrict.ts, 78, 11)) +>Tag2 : Symbol(Tag2, Decl(intersectionReductionStrict.ts, 71, 18)) s1 = s2; ->s1 : Symbol(s1, Decl(intersectionReductionStrict.ts, 45, 11)) ->s2 : Symbol(s2, Decl(intersectionReductionStrict.ts, 46, 11)) +>s1 : Symbol(s1, Decl(intersectionReductionStrict.ts, 74, 11)) +>s2 : Symbol(s2, Decl(intersectionReductionStrict.ts, 75, 11)) s2 = s1; ->s2 : Symbol(s2, Decl(intersectionReductionStrict.ts, 46, 11)) ->s1 : Symbol(s1, Decl(intersectionReductionStrict.ts, 45, 11)) +>s2 : Symbol(s2, Decl(intersectionReductionStrict.ts, 75, 11)) +>s1 : Symbol(s1, Decl(intersectionReductionStrict.ts, 74, 11)) t1 = t2; ->t1 : Symbol(t1, Decl(intersectionReductionStrict.ts, 48, 11)) ->t2 : Symbol(t2, Decl(intersectionReductionStrict.ts, 49, 11)) +>t1 : Symbol(t1, Decl(intersectionReductionStrict.ts, 77, 11)) +>t2 : Symbol(t2, Decl(intersectionReductionStrict.ts, 78, 11)) t2 = t1; ->t2 : Symbol(t2, Decl(intersectionReductionStrict.ts, 49, 11)) ->t1 : Symbol(t1, Decl(intersectionReductionStrict.ts, 48, 11)) +>t2 : Symbol(t2, Decl(intersectionReductionStrict.ts, 78, 11)) +>t1 : Symbol(t1, Decl(intersectionReductionStrict.ts, 77, 11)) + +// Repro from #36736 + +const f1 = (t: "a" | ("b" & "c")): "a" => t; +>f1 : Symbol(f1, Decl(intersectionReductionStrict.ts, 88, 5)) +>t : Symbol(t, Decl(intersectionReductionStrict.ts, 88, 12)) +>t : Symbol(t, Decl(intersectionReductionStrict.ts, 88, 12)) + +type Container = { +>Container : Symbol(Container, Decl(intersectionReductionStrict.ts, 88, 44)) +>Type : Symbol(Type, Decl(intersectionReductionStrict.ts, 90, 15)) + + type: Type; +>type : Symbol(type, Decl(intersectionReductionStrict.ts, 90, 39)) +>Type : Symbol(Type, Decl(intersectionReductionStrict.ts, 90, 15)) +} + +const f2 = (t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t; +>f2 : Symbol(f2, Decl(intersectionReductionStrict.ts, 94, 5)) +>t : Symbol(t, Decl(intersectionReductionStrict.ts, 94, 12)) +>Container : Symbol(Container, Decl(intersectionReductionStrict.ts, 88, 44)) +>Container : Symbol(Container, Decl(intersectionReductionStrict.ts, 88, 44)) +>Container : Symbol(Container, Decl(intersectionReductionStrict.ts, 88, 44)) +>Container : Symbol(Container, Decl(intersectionReductionStrict.ts, 88, 44)) +>t : Symbol(t, Decl(intersectionReductionStrict.ts, 94, 12)) + +const f3 = (t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t; +>f3 : Symbol(f3, Decl(intersectionReductionStrict.ts, 95, 5)) +>t : Symbol(t, Decl(intersectionReductionStrict.ts, 95, 12)) +>Container : Symbol(Container, Decl(intersectionReductionStrict.ts, 88, 44)) +>Container : Symbol(Container, Decl(intersectionReductionStrict.ts, 88, 44)) +>dataB : Symbol(dataB, Decl(intersectionReductionStrict.ts, 95, 51)) +>Container : Symbol(Container, Decl(intersectionReductionStrict.ts, 88, 44)) +>Container : Symbol(Container, Decl(intersectionReductionStrict.ts, 88, 44)) +>t : Symbol(t, Decl(intersectionReductionStrict.ts, 95, 12)) + +const f4 = (t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t; +>f4 : Symbol(f4, Decl(intersectionReductionStrict.ts, 96, 5)) +>t : Symbol(t, Decl(intersectionReductionStrict.ts, 96, 12)) +>Container : Symbol(Container, Decl(intersectionReductionStrict.ts, 88, 44)) +>dataB : Symbol(dataB, Decl(intersectionReductionStrict.ts, 96, 43)) +>Container : Symbol(Container, Decl(intersectionReductionStrict.ts, 88, 44)) +>t : Symbol(t, Decl(intersectionReductionStrict.ts, 96, 12)) diff --git a/tests/baselines/reference/intersectionReductionStrict.types b/tests/baselines/reference/intersectionReductionStrict.types index 8227f6b407259..73ad61fb9cc6c 100644 --- a/tests/baselines/reference/intersectionReductionStrict.types +++ b/tests/baselines/reference/intersectionReductionStrict.types @@ -88,6 +88,90 @@ type X6 = X | symbol & string; type X7 = X | void & string; >X7 : X +type A = { kind: 'a', foo: string }; +>A : A +>kind : "a" +>foo : string + +type B = { kind: 'b', foo: number }; +>B : B +>kind : "b" +>foo : number + +type C = { kind: 'c', foo: number }; +>C : C +>kind : "c" +>foo : number + +declare let ab: A & B; +>ab : never + +ab.kind; // Error +>ab.kind : any +>ab : never +>kind : any + +declare let x: A | (B & C); // A +>x : A + +let a: A = x; +>a : A +>x : A + +type AB = A & B; // never +>AB : never + +type BC = B & C; // never +>BC : never + +type U1 = Partial; // never +>U1 : never + +type U2 = Readonly; // never +>U2 : never + +type U3 = (A & B)['kind']; // never +>U3 : never + +type U4 = A & B | B & C; // never +>U4 : never + +type U5 = A | B & C; // A +>U5 : A + +type K1 = keyof (A & B); // string | number | symbol +>K1 : string | number | symbol + +type K2 = keyof A | keyof B; // 'kind' | 'foo' +>K2 : "kind" | "foo" + +type Merge1 = { [P in keyof (T & U)]: P extends keyof T ? T[P] : U[P & keyof U] } +>Merge1 : Merge1 + +type Merge2 = { [P in keyof T | keyof U]: P extends keyof T ? T[P] : U[P & keyof U] } +>Merge2 : Merge2 + +type M1 = { a: 1, b: 2 } & { a: 2, c: 3 }; // never +>M1 : never +>a : 1 +>b : 2 +>a : 2 +>c : 3 + +type M2 = Merge1<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // {} +>M2 : Merge1<{ a: 1; b: 2; }, { a: 2; c: 3; }> +>a : 1 +>b : 2 +>a : 2 +>c : 3 + +type M3 = Merge2<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // { a: 1, b: 2, c: 3 } +>M3 : Merge2<{ a: 1; b: 2; }, { a: 2; c: 3; }> +>a : 1 +>b : 2 +>a : 2 +>c : 3 + // Repro from #31663 const x1 = { a: 'foo', b: 42 }; @@ -163,3 +247,38 @@ t2 = t1; >t2 : undefined >t1 : undefined +// Repro from #36736 + +const f1 = (t: "a" | ("b" & "c")): "a" => t; +>f1 : (t: "a") => "a" +>(t: "a" | ("b" & "c")): "a" => t : (t: "a") => "a" +>t : "a" +>t : "a" + +type Container = { +>Container : Container + + type: Type; +>type : Type +} + +const f2 = (t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t; +>f2 : (t: Container<"a">) => Container<"a"> +>(t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t : (t: Container<"a">) => Container<"a"> +>t : Container<"a"> +>t : Container<"a"> + +const f3 = (t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t; +>f3 : (t: Container<"a">) => Container<"a"> +>(t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t : (t: Container<"a">) => Container<"a"> +>t : Container<"a"> +>dataB : boolean +>t : Container<"a"> + +const f4 = (t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t; +>f4 : (t: number) => number +>(t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t : (t: number) => number +>t : number +>dataB : boolean +>t : number + diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 5b0da12ed906a..f253d6c095472 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -565,7 +565,7 @@ let overwriteId: { id: string, a: number, c: number, d: string } = >d : string f({ a: 1, id: true }, { c: 1, d: 'no' }) ->f({ a: 1, id: true }, { c: 1, d: 'no' }) : { a: number; id: boolean; } & { c: number; d: string; } & { id: string; } +>f({ a: 1, id: true }, { c: 1, d: 'no' }) : never >f : (t: T, u: U) => T & U & { id: string; } >{ a: 1, id: true } : { a: number; id: true; } >a : number diff --git a/tests/baselines/reference/recursiveMappedTypes.errors.txt b/tests/baselines/reference/recursiveMappedTypes.errors.txt index 43a0e736d256f..ee8b0b02ddb84 100644 --- a/tests/baselines/reference/recursiveMappedTypes.errors.txt +++ b/tests/baselines/reference/recursiveMappedTypes.errors.txt @@ -6,9 +6,10 @@ tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(11,6): error TS2456 tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(12,11): error TS2313: Type parameter 'K' has a circular constraint. tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(20,19): error TS2589: Type instantiation is excessively deep and possibly infinite. tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(66,25): error TS2313: Type parameter 'P' has a circular constraint. +tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(79,1): error TS2615: Type of property '"each"' circularly references itself in mapped type '{ type: never; minimum_count: never; maximum_count: never; collapsable?: never; each: never; }'. -==== tests/cases/conformance/types/mapped/recursiveMappedTypes.ts (8 errors) ==== +==== tests/cases/conformance/types/mapped/recursiveMappedTypes.ts (9 errors) ==== // Recursive mapped types simply appear empty type Recurse = { @@ -106,4 +107,6 @@ tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(66,25): error TS231 declare let x: ListChild; x.type; + ~~~~~~ +!!! error TS2615: Type of property '"each"' circularly references itself in mapped type '{ type: never; minimum_count: never; maximum_count: never; collapsable?: never; each: never; }'. \ No newline at end of file diff --git a/tests/baselines/reference/stringLiteralTypesAsTags01.types b/tests/baselines/reference/stringLiteralTypesAsTags01.types index eddba6fbd0987..8a101a7a00ead 100644 --- a/tests/baselines/reference/stringLiteralTypesAsTags01.types +++ b/tests/baselines/reference/stringLiteralTypesAsTags01.types @@ -93,6 +93,6 @@ if (!hasKind(x, "B")) { } else { let d = x; ->d : A & B ->x : A & B +>d : never +>x : never } diff --git a/tests/baselines/reference/stringLiteralTypesAsTags02.types b/tests/baselines/reference/stringLiteralTypesAsTags02.types index 40a9cd840f0ab..d6c183c67a465 100644 --- a/tests/baselines/reference/stringLiteralTypesAsTags02.types +++ b/tests/baselines/reference/stringLiteralTypesAsTags02.types @@ -88,6 +88,6 @@ if (!hasKind(x, "B")) { } else { let d = x; ->d : A & B ->x : A & B +>d : never +>x : never } diff --git a/tests/baselines/reference/stringLiteralTypesAsTags03.types b/tests/baselines/reference/stringLiteralTypesAsTags03.types index 392174f627f88..ef675ab39e7a0 100644 --- a/tests/baselines/reference/stringLiteralTypesAsTags03.types +++ b/tests/baselines/reference/stringLiteralTypesAsTags03.types @@ -92,6 +92,6 @@ if (!hasKind(x, "B")) { } else { let d = x; ->d : A & B ->x : A & B +>d : never +>x : never } diff --git a/tests/baselines/reference/tsxUnionElementType1.errors.txt b/tests/baselines/reference/tsxUnionElementType1.errors.txt index e2f5bef633392..1a5b6041baf41 100644 --- a/tests/baselines/reference/tsxUnionElementType1.errors.txt +++ b/tests/baselines/reference/tsxUnionElementType1.errors.txt @@ -15,5 +15,4 @@ tests/cases/conformance/jsx/file.tsx(12,10): error TS2322: Type 'true' is not as var SFCComp = SFC1 || SFC2; ~ -!!! error TS2322: Type 'true' is not assignable to type 'never'. -!!! related TS6500 tests/cases/conformance/jsx/file.tsx:3:23: The expected type comes from property 'x' which is declared here on type 'IntrinsicAttributes & { x: number; } & { x: boolean; }' \ No newline at end of file +!!! error TS2322: Type 'true' is not assignable to type 'never'. \ No newline at end of file diff --git a/tests/baselines/reference/tsxUnionElementType2.errors.txt b/tests/baselines/reference/tsxUnionElementType2.errors.txt index 87f1d7fc2dc58..75dd05a0cd6cf 100644 --- a/tests/baselines/reference/tsxUnionElementType2.errors.txt +++ b/tests/baselines/reference/tsxUnionElementType2.errors.txt @@ -15,5 +15,4 @@ tests/cases/conformance/jsx/file.tsx(12,10): error TS2322: Type 'string' is not var SFCComp = SFC1 || SFC2; ~ -!!! error TS2322: Type 'string' is not assignable to type 'never'. -!!! related TS6500 tests/cases/conformance/jsx/file.tsx:3:23: The expected type comes from property 'x' which is declared here on type 'IntrinsicAttributes & { x: number; } & { x: boolean; }' \ No newline at end of file +!!! error TS2322: Type 'string' is not assignable to type 'never'. \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt b/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt new file mode 100644 index 0000000000000..dfcb8a598dae5 --- /dev/null +++ b/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt @@ -0,0 +1,14 @@ +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts(7,20): error TS2339: Property 'global' does not exist on type 'never'. + + +==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts (1 errors) ==== + interface I { global: string; } + var result: I; + var result2: I; + + if (!(result instanceof RegExp)) { + result = result2; + } else if (!result.global) { + ~~~~~~ +!!! error TS2339: Property 'global' does not exist on type 'never'. + } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsWithInstanceOf.symbols b/tests/baselines/reference/typeGuardsWithInstanceOf.symbols index 90be23463b9bf..431e8c5ae91be 100644 --- a/tests/baselines/reference/typeGuardsWithInstanceOf.symbols +++ b/tests/baselines/reference/typeGuardsWithInstanceOf.symbols @@ -20,7 +20,5 @@ if (!(result instanceof RegExp)) { >result2 : Symbol(result2, Decl(typeGuardsWithInstanceOf.ts, 2, 3)) } else if (!result.global) { ->result.global : Symbol(global, Decl(typeGuardsWithInstanceOf.ts, 0, 13), Decl(lib.es5.d.ts, --, --)) >result : Symbol(result, Decl(typeGuardsWithInstanceOf.ts, 1, 3)) ->global : Symbol(global, Decl(typeGuardsWithInstanceOf.ts, 0, 13), Decl(lib.es5.d.ts, --, --)) } diff --git a/tests/baselines/reference/typeGuardsWithInstanceOf.types b/tests/baselines/reference/typeGuardsWithInstanceOf.types index fa425123812af..fbc7636d5fcbc 100644 --- a/tests/baselines/reference/typeGuardsWithInstanceOf.types +++ b/tests/baselines/reference/typeGuardsWithInstanceOf.types @@ -22,7 +22,7 @@ if (!(result instanceof RegExp)) { } else if (!result.global) { >!result.global : boolean ->result.global : never ->result : I & RegExp ->global : never +>result.global : any +>result : never +>global : any } diff --git a/tests/cases/conformance/types/intersection/intersectionReduction.ts b/tests/cases/conformance/types/intersection/intersectionReduction.ts index 128f6fd067ab7..8aeb110fd5f10 100644 --- a/tests/cases/conformance/types/intersection/intersectionReduction.ts +++ b/tests/cases/conformance/types/intersection/intersectionReduction.ts @@ -32,6 +32,46 @@ type X5 = X | number & object; type X6 = X | symbol & string; type X7 = X | void & string; +type A = { kind: 'a', foo: string }; +type B = { kind: 'b', foo: number }; +type C = { kind: 'c', foo: number }; + +declare let ab: A & B; +ab.kind; // Error + +declare let x: A | (B & C); // A +let a: A = x; + +type AB = A & B; // never +type BC = B & C; // never + +type U1 = Partial; // never +type U2 = Readonly; // never +type U3 = (A & B)['kind']; // never +type U4 = A & B | B & C; // never +type U5 = A | B & C; // A + +type K1 = keyof (A & B); // string | number | symbol +type K2 = keyof A | keyof B; // 'kind' | 'foo' + +type Merge1 = { [P in keyof (T & U)]: P extends keyof T ? T[P] : U[P & keyof U] } +type Merge2 = { [P in keyof T | keyof U]: P extends keyof T ? T[P] : U[P & keyof U] } + +type M1 = { a: 1, b: 2 } & { a: 2, c: 3 }; // never +type M2 = Merge1<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // {} +type M3 = Merge2<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // { a: 1, b: 2, c: 3 } + +type D = { kind: 'd', foo: unknown }; +type E = { kind: 'e', foo: unknown }; + +declare function f10(x: { foo: T }): T; + +declare let a1: A | D; +declare let a2: A | D & E; + +let r1 = f10(a1); // unknown +let r2 = f10(a2); // string + // Repro from #31663 const x1 = { a: 'foo', b: 42 }; @@ -56,3 +96,15 @@ s2 = s1; t1 = t2; t2 = t1; + +// Repro from #36736 + +const f1 = (t: "a" | ("b" & "c")): "a" => t; + +type Container = { + type: Type; +} + +const f2 = (t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t; +const f3 = (t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t; +const f4 = (t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t; diff --git a/tests/cases/conformance/types/intersection/intersectionReductionStrict.ts b/tests/cases/conformance/types/intersection/intersectionReductionStrict.ts index 2136f99db9ff9..4fea85d67120d 100644 --- a/tests/cases/conformance/types/intersection/intersectionReductionStrict.ts +++ b/tests/cases/conformance/types/intersection/intersectionReductionStrict.ts @@ -32,6 +32,35 @@ type X5 = X | number & object; type X6 = X | symbol & string; type X7 = X | void & string; +type A = { kind: 'a', foo: string }; +type B = { kind: 'b', foo: number }; +type C = { kind: 'c', foo: number }; + +declare let ab: A & B; +ab.kind; // Error + +declare let x: A | (B & C); // A +let a: A = x; + +type AB = A & B; // never +type BC = B & C; // never + +type U1 = Partial; // never +type U2 = Readonly; // never +type U3 = (A & B)['kind']; // never +type U4 = A & B | B & C; // never +type U5 = A | B & C; // A + +type K1 = keyof (A & B); // string | number | symbol +type K2 = keyof A | keyof B; // 'kind' | 'foo' + +type Merge1 = { [P in keyof (T & U)]: P extends keyof T ? T[P] : U[P & keyof U] } +type Merge2 = { [P in keyof T | keyof U]: P extends keyof T ? T[P] : U[P & keyof U] } + +type M1 = { a: 1, b: 2 } & { a: 2, c: 3 }; // never +type M2 = Merge1<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // {} +type M3 = Merge2<{ a: 1, b: 2 }, { a: 2, c: 3 }>; // { a: 1, b: 2, c: 3 } + // Repro from #31663 const x1 = { a: 'foo', b: 42 }; @@ -56,3 +85,15 @@ s2 = s1; t1 = t2; t2 = t1; + +// Repro from #36736 + +const f1 = (t: "a" | ("b" & "c")): "a" => t; + +type Container = { + type: Type; +} + +const f2 = (t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t; +const f3 = (t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t; +const f4 = (t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t; diff --git a/tests/cases/conformance/types/union/discriminatedUnionTypes2.ts b/tests/cases/conformance/types/union/discriminatedUnionTypes2.ts index b73fdb8f0ab83..6ef85b2406a51 100644 --- a/tests/cases/conformance/types/union/discriminatedUnionTypes2.ts +++ b/tests/cases/conformance/types/union/discriminatedUnionTypes2.ts @@ -131,7 +131,7 @@ function foo1(x: RuntimeValue & { type: 'number' }) { x.value; // number } else { - x.value; // Error, x is never + x.value; // number } } diff --git a/tests/cases/fourslash/quickInfoInheritedJSDoc.ts b/tests/cases/fourslash/quickInfoInheritedJSDoc.ts deleted file mode 100644 index 7b1f54815b76b..0000000000000 --- a/tests/cases/fourslash/quickInfoInheritedJSDoc.ts +++ /dev/null @@ -1,14 +0,0 @@ -/// -// #32708 - -////interface I { -//// /** only once please */ -//// t: T -////} -////interface C extends I { -//// t: T -////} -////declare var cnsb: C & C & C; -////cnsb.t/**/ - -verify.quickInfoAt("", "(property) C.t: never", "only once please"); diff --git a/tests/cases/fourslash/tsxCompletionUnionElementType.ts b/tests/cases/fourslash/tsxCompletionUnionElementType.ts deleted file mode 100644 index b554d3851798d..0000000000000 --- a/tests/cases/fourslash/tsxCompletionUnionElementType.ts +++ /dev/null @@ -1,22 +0,0 @@ -/// - -//@Filename: file.tsx -// @jsx: preserve -// @skipLibCheck: true - -//// declare module JSX { -//// interface Element { } -//// interface IntrinsicElements { -//// } -//// interface ElementAttributesProperty { props; } -//// } -//// function SFC1(prop: { x: number }) { -//// return
hello
; -//// }; -//// function SFC2(prop: { x: boolean }) { -//// return

World

; -//// } -//// var SFCComp = SFC1 || SFC2; -//// - -verify.completions({ marker: "", exact: ["x"] });