diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f9c87e949615d..dbb0180dfdb80 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -678,6 +678,7 @@ namespace ts { let _jsxNamespace: __String; let _jsxFactoryEntity: EntityName | undefined; + let outofbandVarianceMarkerHandler: ((onlyUnreliable: boolean) => void) | undefined; const subtypeRelation = createMap(); const assignableRelation = createMap(); @@ -12062,12 +12063,14 @@ namespace ts { } if (!ignoreReturnTypes) { - const targetReturnType = (target.declaration && isJSConstructor(target.declaration)) ? + // If a signature reolution is already in-flight, skip issuing a circularity error + // here and just use the `any` type directly + const targetReturnType = isResolvingReturnTypeOfSignature(target) ? anyType : (target.declaration && isJSConstructor(target.declaration)) ? getJSClassType(target.declaration.symbol)! : getReturnTypeOfSignature(target); if (targetReturnType === voidType) { return result; } - const sourceReturnType = (source.declaration && isJSConstructor(source.declaration)) ? + const sourceReturnType = isResolvingReturnTypeOfSignature(source) ? anyType : (source.declaration && isJSConstructor(source.declaration)) ? getJSClassType(source.declaration.symbol)! : getReturnTypeOfSignature(source); // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions @@ -12852,7 +12855,7 @@ namespace ts { return result; } - function typeArgumentsRelatedTo(sources: ReadonlyArray = emptyArray, targets: ReadonlyArray = emptyArray, variances: ReadonlyArray = emptyArray, reportErrors: boolean): Ternary { + function typeArgumentsRelatedTo(sources: ReadonlyArray = emptyArray, targets: ReadonlyArray = emptyArray, variances: ReadonlyArray = emptyArray, reportErrors: boolean): Ternary { if (sources.length !== targets.length && relation === identityRelation) { return Ternary.False; } @@ -12862,19 +12865,26 @@ namespace ts { // When variance information isn't available we default to covariance. This happens // in the process of computing variance information for recursive types and when // comparing 'this' type arguments. - const variance = i < variances.length ? variances[i] : Variance.Covariant; + const varianceFlags = i < variances.length ? variances[i] : VarianceFlags.Covariant; + const variance = varianceFlags & VarianceFlags.VarianceMask; // We ignore arguments for independent type parameters (because they're never witnessed). - if (variance !== Variance.Independent) { + if (variance !== VarianceFlags.Independent) { const s = sources[i]; const t = targets[i]; let related = Ternary.True; - if (variance === Variance.Covariant) { + if (varianceFlags & VarianceFlags.Unmeasurable) { + // Even an `Unmeasurable` variance works out without a structural check if the source and target are _identical_. + // We can't simply assume invariance, because `Unmeasurable` marks nonlinear relations, for example, a relation tained by + // the `-?` modifier in a mapped type (where, no matter how the inputs are related, the outputs still might not be) + related = relation === identityRelation ? isRelatedTo(s, t, /*reportErrors*/ false) : compareTypesIdentical(s, t); + } + else if (variance === VarianceFlags.Covariant) { related = isRelatedTo(s, t, reportErrors); } - else if (variance === Variance.Contravariant) { + else if (variance === VarianceFlags.Contravariant) { related = isRelatedTo(t, s, reportErrors); } - else if (variance === Variance.Bivariant) { + else if (variance === VarianceFlags.Bivariant) { // In the bivariant case we first compare contravariantly without reporting // errors. Then, if that doesn't succeed, we compare covariantly with error // reporting. Thus, error elaboration will be based on the the covariant check, @@ -13254,21 +13264,20 @@ namespace ts { } return Ternary.False; - function isNonGeneric(type: Type) { - // If we're already in identity relationship checking, we should use `isRelatedTo` - // to catch the `Maybe` from an excessively deep type (which we then assume means - // that the type could possibly contain a generic) - if (relation === identityRelation) { - return isRelatedTo(type, getPermissiveInstantiation(type)) === Ternary.True; - } - return isTypeIdenticalTo(type, getPermissiveInstantiation(type)); - } - - function relateVariances(sourceTypeArguments: ReadonlyArray | undefined, targetTypeArguments: ReadonlyArray | undefined, variances: Variance[]) { + function relateVariances(sourceTypeArguments: ReadonlyArray | undefined, targetTypeArguments: ReadonlyArray | undefined, variances: VarianceFlags[]) { if (result = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors)) { return result; } - const allowStructuralFallback = (targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances)) || isNonGeneric(source) || isNonGeneric(target); + if (some(variances, v => !!(v & VarianceFlags.AllowsStructuralFallback))) { + // If some type parameter was `Unmeasurable` or `Unreliable`, and we couldn't pass by assuming it was identical, then we + // have to allow a structural fallback check + // We elide the variance-based error elaborations, since those might not be too helpful, since we'll potentially + // be assuming identity of the type parameter. + originalErrorInfo = undefined; + errorInfo = saveErrorInfo; + return undefined; + } + const allowStructuralFallback = targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances); varianceCheckFailed = !allowStructuralFallback; // The type arguments did not relate appropriately, but it may be because we have no variance // information (in which case typeArgumentsRelatedTo defaulted to covariance for all type @@ -13286,7 +13295,7 @@ namespace ts { // reveal the reason). // We can switch on `reportErrors` here, since varianceCheckFailed guarantees we return `False`, // we can return `False` early here to skip calculating the structural error message we don't need. - if (varianceCheckFailed && !(reportErrors && some(variances, v => v === Variance.Invariant))) { + if (varianceCheckFailed && !(reportErrors && some(variances, v => (v & VarianceFlags.VarianceMask) === VarianceFlags.Invariant))) { return Ternary.False; } // We remember the original error information so we can restore it in case the structural @@ -13298,6 +13307,20 @@ namespace ts { } } + function reportUnmeasurableMarkers(p: TypeParameter) { + if (outofbandVarianceMarkerHandler && (p === markerSuperType || p === markerSubType || p === markerOtherType)) { + outofbandVarianceMarkerHandler(/*onlyUnreliable*/ false); + } + return p; + } + + function reportUnreliableMarkers(p: TypeParameter) { + if (outofbandVarianceMarkerHandler && (p === markerSuperType || p === markerSubType || p === markerOtherType)) { + outofbandVarianceMarkerHandler(/*onlyUnreliable*/ true); + } + return p; + } + // A type [P in S]: X is related to a type [Q in T]: Y if T is related to S and X' is // related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice // that S and T are contra-variant whereas X and Y are co-variant. @@ -13306,7 +13329,9 @@ namespace ts { getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target)); if (modifiersRelated) { let result: Ternary; - if (result = isRelatedTo(getConstraintTypeFromMappedType(target), getConstraintTypeFromMappedType(source), reportErrors)) { + const targetConstraint = getConstraintTypeFromMappedType(target); + const sourceConstraint = instantiateType(getConstraintTypeFromMappedType(source), getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMarkers : reportUnreliableMarkers); + if (result = isRelatedTo(targetConstraint, sourceConstraint, reportErrors)) { const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [getTypeParameterFromMappedType(target)]); return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(source), mapper), getTemplateTypeFromMappedType(target), reportErrors); } @@ -13896,26 +13921,45 @@ namespace ts { // instantiations of the generic type for type arguments with known relations. The function // returns the emptyArray singleton if we're not in strictFunctionTypes mode or if the function // has been invoked recursively for the given generic type. - function getVariancesWorker(typeParameters: ReadonlyArray = emptyArray, cache: TCache, createMarkerType: (input: TCache, param: TypeParameter, marker: Type) => Type): Variance[] { + function getVariancesWorker(typeParameters: ReadonlyArray = emptyArray, cache: TCache, createMarkerType: (input: TCache, param: TypeParameter, marker: Type) => Type): VarianceFlags[] { let variances = cache.variances; if (!variances) { // The emptyArray singleton is used to signal a recursive invocation. cache.variances = emptyArray; variances = []; for (const tp of typeParameters) { + let unmeasurable = false; + let unreliable = false; + const oldHandler = outofbandVarianceMarkerHandler; + outofbandVarianceMarkerHandler = (onlyUnreliable) => onlyUnreliable ? unreliable = true : unmeasurable = true; // We first compare instantiations where the type parameter is replaced with // marker types that have a known subtype relationship. From this we can infer // invariance, covariance, contravariance or bivariance. const typeWithSuper = createMarkerType(cache, tp, markerSuperType); const typeWithSub = createMarkerType(cache, tp, markerSubType); - let variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? Variance.Covariant : 0) | - (isTypeAssignableTo(typeWithSuper, typeWithSub) ? Variance.Contravariant : 0); + let variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? VarianceFlags.Covariant : 0) | + (isTypeAssignableTo(typeWithSuper, typeWithSub) ? VarianceFlags.Contravariant : 0); // If the instantiations appear to be related bivariantly it may be because the // type parameter is independent (i.e. it isn't witnessed anywhere in the generic // type). To determine this we compare instantiations where the type parameter is // replaced with marker types that are known to be unrelated. - if (variance === Variance.Bivariant && isTypeAssignableTo(createMarkerType(cache, tp, markerOtherType), typeWithSuper)) { - variance = Variance.Independent; + if (variance === VarianceFlags.Bivariant && isTypeAssignableTo(createMarkerType(cache, tp, markerOtherType), typeWithSuper)) { + variance = VarianceFlags.Independent; + } + outofbandVarianceMarkerHandler = oldHandler; + if (unmeasurable || unreliable) { + if (unmeasurable) { + variance |= VarianceFlags.Unmeasurable; + } + if (unreliable) { + variance |= VarianceFlags.Unreliable; + } + const covariantID = getRelationKey(typeWithSub, typeWithSuper, assignableRelation); + const contravariantID = getRelationKey(typeWithSuper, typeWithSub, assignableRelation); + // We delete the results of these checks, as we want them to actually be run, see the `Unmeasurable` variance we cache, + // And then fall back to a structural result. + assignableRelation.delete(covariantID); + assignableRelation.delete(contravariantID); } variances.push(variance); } @@ -13924,7 +13968,7 @@ namespace ts { return variances; } - function getVariances(type: GenericType): Variance[] { + function getVariances(type: GenericType): VarianceFlags[] { // Arrays and tuples are known to be covariant, no need to spend time computing this (emptyArray implies covariance for all parameters) if (type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple) { return emptyArray; @@ -13934,9 +13978,9 @@ namespace ts { // Return true if the given type reference has a 'void' type argument for a covariant type parameter. // See comment at call in recursiveTypeRelatedTo for when this case matters. - function hasCovariantVoidArgument(typeArguments: ReadonlyArray, variances: Variance[]): boolean { + function hasCovariantVoidArgument(typeArguments: ReadonlyArray, variances: VarianceFlags[]): boolean { for (let i = 0; i < variances.length; i++) { - if (variances[i] === Variance.Covariant && typeArguments[i].flags & TypeFlags.Void) { + if ((variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Covariant && typeArguments[i].flags & TypeFlags.Void) { return true; } } @@ -15109,7 +15153,7 @@ namespace ts { const count = sourceTypes.length < targetTypes.length ? sourceTypes.length : targetTypes.length; const variances = getVariances((source).target); for (let i = 0; i < count; i++) { - if (i < variances.length && variances[i] === Variance.Contravariant) { + if (i < variances.length && (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Contravariant) { inferFromContravariantTypes(sourceTypes[i], targetTypes[i]); } else { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5e2d6aba474ee..af4194a9c6949 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3735,7 +3735,7 @@ namespace ts { specifierCache?: Map; // For symbols corresponding to external modules, a cache of incoming path -> module specifier name mappings extendedContainers?: Symbol[]; // Containers (other than the parent) which this symbol is aliased in extendedContainersByFile?: Map; // Containers (other than the parent) which this symbol is aliased in - variances?: Variance[]; // Alias symbol type argument variance cache + variances?: VarianceFlags[]; // Alias symbol type argument variance cache } /* @internal */ @@ -4131,12 +4131,16 @@ namespace ts { } /* @internal */ - export const enum Variance { - Invariant = 0, // Neither covariant nor contravariant - Covariant = 1, // Covariant - Contravariant = 2, // Contravariant - Bivariant = 3, // Both covariant and contravariant - Independent = 4, // Unwitnessed type parameter + export const enum VarianceFlags { + Invariant = 0, // Neither covariant nor contravariant + Covariant = 1 << 0, // Covariant + Contravariant = 1 << 1, // Contravariant + Bivariant = Covariant | Contravariant, // Both covariant and contravariant + Independent = 1 << 2, // Unwitnessed type parameter + VarianceMask = Invariant | Covariant | Contravariant | Independent, // Mask containing all measured variances without the unmeasurable flag + Unmeasurable = 1 << 3, // Variance result is unusable - relationship relies on structural comparisons which are not reflected in generic relationships + Unreliable = 1 << 4, // Variance result is unreliable - relationship relies on structural comparisons which are not reflected in generic relationships + AllowsStructuralFallback = Unmeasurable | Unreliable, } // Generic class and interface types @@ -4144,7 +4148,7 @@ namespace ts { /* @internal */ instantiations: Map; // Generic instantiation cache /* @internal */ - variances?: Variance[]; // Variance of each type parameter + variances?: VarianceFlags[]; // Variance of each type parameter } export interface TupleType extends GenericType { diff --git a/tests/baselines/reference/checkInfiniteExpansionTermination.errors.txt b/tests/baselines/reference/checkInfiniteExpansionTermination.errors.txt new file mode 100644 index 0000000000000..014087ff6275e --- /dev/null +++ b/tests/baselines/reference/checkInfiniteExpansionTermination.errors.txt @@ -0,0 +1,32 @@ +tests/cases/compiler/checkInfiniteExpansionTermination.ts(16,1): error TS2322: Type 'ISubject' is not assignable to type 'IObservable'. + Types of property 'n' are incompatible. + Type 'IObservable' is not assignable to type 'IObservable'. + Type 'Bar[]' is not assignable to type 'Foo[]'. + Property 'x' is missing in type 'Bar' but required in type 'Foo'. + + +==== tests/cases/compiler/checkInfiniteExpansionTermination.ts (1 errors) ==== + // Regression test for #1002 + // Before fix this code would cause infinite loop + + interface IObservable { + n: IObservable; // Needed, must be T[] + } + + // Needed + interface ISubject extends IObservable { } + + interface Foo { x } + interface Bar { y } + + var values: IObservable; + var values2: ISubject; + values = values2; + ~~~~~~ +!!! error TS2322: Type 'ISubject' is not assignable to type 'IObservable'. +!!! error TS2322: Types of property 'n' are incompatible. +!!! error TS2322: Type 'IObservable' is not assignable to type 'IObservable'. +!!! error TS2322: Type 'Bar[]' is not assignable to type 'Foo[]'. +!!! error TS2322: Property 'x' is missing in type 'Bar' but required in type 'Foo'. +!!! related TS2728 tests/cases/compiler/checkInfiniteExpansionTermination.ts:11:17: 'x' is declared here. + \ No newline at end of file diff --git a/tests/baselines/reference/conditionalTypes1.errors.txt b/tests/baselines/reference/conditionalTypes1.errors.txt index c84ce90642a3a..7abcf55b8e7cb 100644 --- a/tests/baselines/reference/conditionalTypes1.errors.txt +++ b/tests/baselines/reference/conditionalTypes1.errors.txt @@ -19,12 +19,8 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(104,5): error TS2 'Pick' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'. tests/cases/conformance/types/conditional/conditionalTypes1.ts(106,5): error TS2322: Type 'Pick' is not assignable to type 'Pick'. Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. - Type 'keyof T' is not assignable to type 'never'. - Type 'string | number | symbol' is not assignable to type 'never'. - Type 'string' is not assignable to type 'never'. tests/cases/conformance/types/conditional/conditionalTypes1.ts(108,5): error TS2322: Type 'Pick' is not assignable to type 'Pick'. Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. - Type 'keyof T' is not assignable to type 'never'. tests/cases/conformance/types/conditional/conditionalTypes1.ts(114,5): error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. Type 'string | number | symbol' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. Type 'string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. @@ -195,15 +191,11 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS ~ !!! error TS2322: Type 'Pick' is not assignable to type 'Pick'. !!! error TS2322: Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. -!!! error TS2322: Type 'keyof T' is not assignable to type 'never'. -!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'never'. -!!! error TS2322: Type 'string' is not assignable to type 'never'. z = x; z = y; // Error ~ !!! error TS2322: Type 'Pick' is not assignable to type 'Pick'. !!! error TS2322: Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. -!!! error TS2322: Type 'keyof T' is not assignable to type 'never'. } function f8(x: keyof T, y: FunctionPropertyNames, z: NonFunctionPropertyNames) { diff --git a/tests/baselines/reference/consistentAliasVsNonAliasRecordBehavior.errors.txt b/tests/baselines/reference/consistentAliasVsNonAliasRecordBehavior.errors.txt new file mode 100644 index 0000000000000..76de0b10e47cb --- /dev/null +++ b/tests/baselines/reference/consistentAliasVsNonAliasRecordBehavior.errors.txt @@ -0,0 +1,55 @@ +tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(18,5): error TS2741: Property 'a' is missing in type 'Record' but required in type 'Record2<"a", string>'. +tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(22,5): error TS2741: Property 'a' is missing in type 'Record2' but required in type 'Record<"a", string>'. +tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(34,5): error TS2741: Property 'a' is missing in type 'Record' but required in type 'Record2<"a", T>'. +tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(38,5): error TS2741: Property 'a' is missing in type 'Record2' but required in type 'Record<"a", T>'. + + +==== tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts (4 errors) ==== + // TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being + // by incorrect variance-based relationships + // Ref: https://github.com/Microsoft/TypeScript/issues/29698 + + type Record2 = { + [P in K]: T; + }; + + function defaultRecord(x: Record<'a', string>, y: Record) { + x = y; // no error, but error expected. + } + + function customRecord(x: Record2<'a', string>, y: Record2) { + x = y; // no error, but error expected. + } + + function mixed1(x: Record2<'a', string>, y: Record) { + x = y; // error + ~ +!!! error TS2741: Property 'a' is missing in type 'Record' but required in type 'Record2<"a", string>'. + } + + function mixed2(x: Record<'a', string>, y: Record2) { + x = y; // error + ~ +!!! error TS2741: Property 'a' is missing in type 'Record2' but required in type 'Record<"a", string>'. + } + + function defaultRecord2(x: Record<'a', T>, y: Record) { + x = y; // no error, but error expected. + } + + function customRecord2(x: Record2<'a', T>, y: Record2) { + x = y; // no error, but error expected. + } + + function mixed3(x: Record2<'a', T>, y: Record) { + x = y; // error + ~ +!!! error TS2741: Property 'a' is missing in type 'Record' but required in type 'Record2<"a", T>'. + } + + function mixed4(x: Record<'a', T>, y: Record2) { + x = y; // error + ~ +!!! error TS2741: Property 'a' is missing in type 'Record2' but required in type 'Record<"a", T>'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/consistentAliasVsNonAliasRecordBehavior.js b/tests/baselines/reference/consistentAliasVsNonAliasRecordBehavior.js new file mode 100644 index 0000000000000..0e127e3acb7c5 --- /dev/null +++ b/tests/baselines/reference/consistentAliasVsNonAliasRecordBehavior.js @@ -0,0 +1,70 @@ +//// [consistentAliasVsNonAliasRecordBehavior.ts] +// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being +// by incorrect variance-based relationships +// Ref: https://github.com/Microsoft/TypeScript/issues/29698 + +type Record2 = { + [P in K]: T; +}; + +function defaultRecord(x: Record<'a', string>, y: Record) { + x = y; // no error, but error expected. +} + +function customRecord(x: Record2<'a', string>, y: Record2) { + x = y; // no error, but error expected. +} + +function mixed1(x: Record2<'a', string>, y: Record) { + x = y; // error +} + +function mixed2(x: Record<'a', string>, y: Record2) { + x = y; // error +} + +function defaultRecord2(x: Record<'a', T>, y: Record) { + x = y; // no error, but error expected. +} + +function customRecord2(x: Record2<'a', T>, y: Record2) { + x = y; // no error, but error expected. +} + +function mixed3(x: Record2<'a', T>, y: Record) { + x = y; // error +} + +function mixed4(x: Record<'a', T>, y: Record2) { + x = y; // error +} + + +//// [consistentAliasVsNonAliasRecordBehavior.js] +// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being +// by incorrect variance-based relationships +// Ref: https://github.com/Microsoft/TypeScript/issues/29698 +function defaultRecord(x, y) { + x = y; // no error, but error expected. +} +function customRecord(x, y) { + x = y; // no error, but error expected. +} +function mixed1(x, y) { + x = y; // error +} +function mixed2(x, y) { + x = y; // error +} +function defaultRecord2(x, y) { + x = y; // no error, but error expected. +} +function customRecord2(x, y) { + x = y; // no error, but error expected. +} +function mixed3(x, y) { + x = y; // error +} +function mixed4(x, y) { + x = y; // error +} diff --git a/tests/baselines/reference/consistentAliasVsNonAliasRecordBehavior.symbols b/tests/baselines/reference/consistentAliasVsNonAliasRecordBehavior.symbols new file mode 100644 index 0000000000000..8757e1371acb5 --- /dev/null +++ b/tests/baselines/reference/consistentAliasVsNonAliasRecordBehavior.symbols @@ -0,0 +1,125 @@ +=== tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts === +// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being +// by incorrect variance-based relationships +// Ref: https://github.com/Microsoft/TypeScript/issues/29698 + +type Record2 = { +>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0)) +>K : Symbol(K, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 4, 13)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 4, 33)) + + [P in K]: T; +>P : Symbol(P, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 5, 5)) +>K : Symbol(K, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 4, 13)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 4, 33)) + +}; + +function defaultRecord(x: Record<'a', string>, y: Record) { +>defaultRecord : Symbol(defaultRecord, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 6, 2)) +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 8, 23)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 8, 46)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + + x = y; // no error, but error expected. +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 8, 23)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 8, 46)) +} + +function customRecord(x: Record2<'a', string>, y: Record2) { +>customRecord : Symbol(customRecord, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 10, 1)) +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 12, 22)) +>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 12, 46)) +>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0)) + + x = y; // no error, but error expected. +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 12, 22)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 12, 46)) +} + +function mixed1(x: Record2<'a', string>, y: Record) { +>mixed1 : Symbol(mixed1, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 14, 1)) +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 16, 16)) +>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 16, 40)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + + x = y; // error +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 16, 16)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 16, 40)) +} + +function mixed2(x: Record<'a', string>, y: Record2) { +>mixed2 : Symbol(mixed2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 18, 1)) +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 20, 16)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 20, 39)) +>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0)) + + x = y; // error +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 20, 16)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 20, 39)) +} + +function defaultRecord2(x: Record<'a', T>, y: Record) { +>defaultRecord2 : Symbol(defaultRecord2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 22, 1)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 24)) +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 27)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 24)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 45)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 24)) + + x = y; // no error, but error expected. +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 27)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 45)) +} + +function customRecord2(x: Record2<'a', T>, y: Record2) { +>customRecord2 : Symbol(customRecord2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 26, 1)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 23)) +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 26)) +>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 23)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 45)) +>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 23)) + + x = y; // no error, but error expected. +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 26)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 45)) +} + +function mixed3(x: Record2<'a', T>, y: Record) { +>mixed3 : Symbol(mixed3, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 30, 1)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 16)) +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 19)) +>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 16)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 38)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 16)) + + x = y; // error +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 19)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 38)) +} + +function mixed4(x: Record<'a', T>, y: Record2) { +>mixed4 : Symbol(mixed4, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 34, 1)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 16)) +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 19)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 16)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 37)) +>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0)) +>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 16)) + + x = y; // error +>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 19)) +>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 37)) +} + diff --git a/tests/baselines/reference/consistentAliasVsNonAliasRecordBehavior.types b/tests/baselines/reference/consistentAliasVsNonAliasRecordBehavior.types new file mode 100644 index 0000000000000..b37089039e1ca --- /dev/null +++ b/tests/baselines/reference/consistentAliasVsNonAliasRecordBehavior.types @@ -0,0 +1,99 @@ +=== tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts === +// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being +// by incorrect variance-based relationships +// Ref: https://github.com/Microsoft/TypeScript/issues/29698 + +type Record2 = { +>Record2 : Record2 + + [P in K]: T; +}; + +function defaultRecord(x: Record<'a', string>, y: Record) { +>defaultRecord : (x: Record<"a", string>, y: Record) => void +>x : Record<"a", string> +>y : Record + + x = y; // no error, but error expected. +>x = y : Record +>x : Record<"a", string> +>y : Record +} + +function customRecord(x: Record2<'a', string>, y: Record2) { +>customRecord : (x: Record2<"a", string>, y: Record2) => void +>x : Record2<"a", string> +>y : Record2 + + x = y; // no error, but error expected. +>x = y : Record2 +>x : Record2<"a", string> +>y : Record2 +} + +function mixed1(x: Record2<'a', string>, y: Record) { +>mixed1 : (x: Record2<"a", string>, y: Record) => void +>x : Record2<"a", string> +>y : Record + + x = y; // error +>x = y : Record +>x : Record2<"a", string> +>y : Record +} + +function mixed2(x: Record<'a', string>, y: Record2) { +>mixed2 : (x: Record<"a", string>, y: Record2) => void +>x : Record<"a", string> +>y : Record2 + + x = y; // error +>x = y : Record2 +>x : Record<"a", string> +>y : Record2 +} + +function defaultRecord2(x: Record<'a', T>, y: Record) { +>defaultRecord2 : (x: Record<"a", T>, y: Record) => void +>x : Record<"a", T> +>y : Record + + x = y; // no error, but error expected. +>x = y : Record +>x : Record<"a", T> +>y : Record +} + +function customRecord2(x: Record2<'a', T>, y: Record2) { +>customRecord2 : (x: Record2<"a", T>, y: Record2) => void +>x : Record2<"a", T> +>y : Record2 + + x = y; // no error, but error expected. +>x = y : Record2 +>x : Record2<"a", T> +>y : Record2 +} + +function mixed3(x: Record2<'a', T>, y: Record) { +>mixed3 : (x: Record2<"a", T>, y: Record) => void +>x : Record2<"a", T> +>y : Record + + x = y; // error +>x = y : Record +>x : Record2<"a", T> +>y : Record +} + +function mixed4(x: Record<'a', T>, y: Record2) { +>mixed4 : (x: Record<"a", T>, y: Record2) => void +>x : Record<"a", T> +>y : Record2 + + x = y; // error +>x = y : Record2 +>x : Record<"a", T> +>y : Record2 +} + diff --git a/tests/baselines/reference/invariantGenericErrorElaboration.errors.txt b/tests/baselines/reference/invariantGenericErrorElaboration.errors.txt new file mode 100644 index 0000000000000..0bd79bcf11d6a --- /dev/null +++ b/tests/baselines/reference/invariantGenericErrorElaboration.errors.txt @@ -0,0 +1,52 @@ +tests/cases/compiler/invariantGenericErrorElaboration.ts(3,7): error TS2322: Type 'Num' is not assignable to type 'Runtype'. + Types of property 'constraint' are incompatible. + Type 'Constraint' is not assignable to type 'Constraint>'. + Types of property 'constraint' are incompatible. + Type 'Constraint>' is not assignable to type 'Constraint>>'. + Types of property 'constraint' are incompatible. + Type 'Constraint>>' is not assignable to type 'Constraint>>>'. + Type 'Constraint>>' is not assignable to type 'Constraint>'. + Types of property 'underlying' are incompatible. + Type 'Constraint>' is not assignable to type 'Constraint'. +tests/cases/compiler/invariantGenericErrorElaboration.ts(4,19): error TS2322: Type 'Num' is not assignable to type 'Runtype'. + + +==== tests/cases/compiler/invariantGenericErrorElaboration.ts (2 errors) ==== + // Repro from #19746 + + const wat: Runtype = Num; + ~~~ +!!! error TS2322: Type 'Num' is not assignable to type 'Runtype'. +!!! error TS2322: Types of property 'constraint' are incompatible. +!!! error TS2322: Type 'Constraint' is not assignable to type 'Constraint>'. +!!! error TS2322: Types of property 'constraint' are incompatible. +!!! error TS2322: Type 'Constraint>' is not assignable to type 'Constraint>>'. +!!! error TS2322: Types of property 'constraint' are incompatible. +!!! error TS2322: Type 'Constraint>>' is not assignable to type 'Constraint>>>'. +!!! error TS2322: Type 'Constraint>>' is not assignable to type 'Constraint>'. +!!! error TS2322: Types of property 'underlying' are incompatible. +!!! error TS2322: Type 'Constraint>' is not assignable to type 'Constraint'. +!!! related TS2728 tests/cases/compiler/invariantGenericErrorElaboration.ts:12:3: 'tag' is declared here. + const Foo = Obj({ foo: Num }) + ~~~ +!!! error TS2322: Type 'Num' is not assignable to type 'Runtype'. +!!! related TS6501 tests/cases/compiler/invariantGenericErrorElaboration.ts:17:34: The expected type comes from this index signature. + + interface Runtype { + constraint: Constraint + witness: A + } + + interface Num extends Runtype { + tag: 'number' + } + declare const Num: Num + + interface Obj }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {} + declare function Obj }>(fields: O): Obj; + + interface Constraint> extends Runtype { + underlying: A, + check: (x: A['witness']) => void, + } + \ No newline at end of file diff --git a/tests/baselines/reference/invariantGenericErrorElaboration.types b/tests/baselines/reference/invariantGenericErrorElaboration.types index 86aec86face81..7c4bdd46d037f 100644 --- a/tests/baselines/reference/invariantGenericErrorElaboration.types +++ b/tests/baselines/reference/invariantGenericErrorElaboration.types @@ -6,8 +6,8 @@ const wat: Runtype = Num; >Num : Num const Foo = Obj({ foo: Num }) ->Foo : Obj<{ foo: Num; }> ->Obj({ foo: Num }) : Obj<{ foo: Num; }> +>Foo : any +>Obj({ foo: Num }) : any >Obj : ; }>(fields: O) => Obj >{ foo: Num } : { foo: Num; } >foo : Num diff --git a/tests/baselines/reference/mappedTypes5.errors.txt b/tests/baselines/reference/mappedTypes5.errors.txt index 3b9f3423941ca..d0c32cd1dd956 100644 --- a/tests/baselines/reference/mappedTypes5.errors.txt +++ b/tests/baselines/reference/mappedTypes5.errors.txt @@ -1,8 +1,6 @@ tests/cases/conformance/types/mapped/mappedTypes5.ts(6,9): error TS2322: Type 'Partial' is not assignable to type 'Readonly'. tests/cases/conformance/types/mapped/mappedTypes5.ts(8,9): error TS2322: Type 'Partial>' is not assignable to type 'Readonly'. tests/cases/conformance/types/mapped/mappedTypes5.ts(9,9): error TS2322: Type 'Readonly>' is not assignable to type 'Readonly'. - Type 'Partial' is not assignable to type 'T'. - 'Partial' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'. ==== tests/cases/conformance/types/mapped/mappedTypes5.ts (3 errors) ==== @@ -21,8 +19,6 @@ tests/cases/conformance/types/mapped/mappedTypes5.ts(9,9): error TS2322: Type 'R let b4: Readonly = rp; // Error ~~ !!! error TS2322: Type 'Readonly>' is not assignable to type 'Readonly'. -!!! error TS2322: Type 'Partial' is not assignable to type 'T'. -!!! error TS2322: 'Partial' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'. let c1: Partial> = p; let c2: Partial> = r; let c3: Partial> = pr; diff --git a/tests/baselines/reference/recursiveTypeComparison.errors.txt b/tests/baselines/reference/recursiveTypeComparison.errors.txt new file mode 100644 index 0000000000000..f647763b2e275 --- /dev/null +++ b/tests/baselines/reference/recursiveTypeComparison.errors.txt @@ -0,0 +1,27 @@ +tests/cases/compiler/recursiveTypeComparison.ts(14,5): error TS2322: Type 'Observable<{}>' is not assignable to type 'Property'. + Types of property 'needThisOne' are incompatible. + Type 'Observable<{}>' is not assignable to type 'Observable'. + Type '{}' is not assignable to type 'number'. + + +==== tests/cases/compiler/recursiveTypeComparison.ts (1 errors) ==== + // Before fix this would take an exceeding long time to complete (#1170) + + interface Observable { + // This member can't be of type T, Property, or Observable + needThisOne: Observable; + // Add more to make it slower + expo1: Property; // 0.31 seconds in check + expo2: Property; // 3.11 seconds + expo3: Property; // 82.28 seconds + } + interface Property extends Observable { } + + var p: Observable<{}>; + var stuck: Property = p; + ~~~~~ +!!! error TS2322: Type 'Observable<{}>' is not assignable to type 'Property'. +!!! error TS2322: Types of property 'needThisOne' are incompatible. +!!! error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable'. +!!! error TS2322: Type '{}' is not assignable to type 'number'. + \ No newline at end of file diff --git a/tests/baselines/reference/requiredMappedTypeModifierTrumpsVariance.errors.txt b/tests/baselines/reference/requiredMappedTypeModifierTrumpsVariance.errors.txt new file mode 100644 index 0000000000000..83871b2909688 --- /dev/null +++ b/tests/baselines/reference/requiredMappedTypeModifierTrumpsVariance.errors.txt @@ -0,0 +1,61 @@ +tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts(5,1): error TS2741: Property 'a' is missing in type 'Required<{ b?: 1; x: 1; }>' but required in type 'Required<{ a?: 1; x: 1; }>'. +tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts(6,1): error TS2741: Property 'b' is missing in type 'Required<{ a?: 1; x: 1; }>' but required in type 'Required<{ b?: 1; x: 1; }>'. +tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts(8,3): error TS2339: Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. +tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts(9,3): error TS2339: Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. +tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts(18,1): error TS2322: Type 'Foo<{ b?: 1; x: 1; }>' is not assignable to type 'Foo<{ a?: 1; x: 1; }>'. + Types of property 'a' are incompatible. + Property 'a' is missing in type 'Required<{ b?: 1; x: 1; }>' but required in type 'Required<{ a?: 1; x: 1; }>'. +tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts(19,1): error TS2322: Type 'Foo<{ a?: 1; x: 1; }>' is not assignable to type 'Foo<{ b?: 1; x: 1; }>'. + Types of property 'a' are incompatible. + Property 'b' is missing in type 'Required<{ a?: 1; x: 1; }>' but required in type 'Required<{ b?: 1; x: 1; }>'. +tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts(21,6): error TS2339: Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. +tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts(22,6): error TS2339: Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. + + +==== tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts (8 errors) ==== + const a: Required<{ a?: 1; x: 1 }> = { a: 1, x: 1 }; + const b: Required<{ b?: 1; x: 1 }> = { b: 1, x: 1 }; + export let A = a; + export let B = b; + A = b; // Should Error + ~ +!!! error TS2741: Property 'a' is missing in type 'Required<{ b?: 1; x: 1; }>' but required in type 'Required<{ a?: 1; x: 1; }>'. +!!! related TS2728 tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts:1:21: 'a' is declared here. + B = a; // Should Error + ~ +!!! error TS2741: Property 'b' is missing in type 'Required<{ a?: 1; x: 1; }>' but required in type 'Required<{ b?: 1; x: 1; }>'. +!!! related TS2728 tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts:2:21: 'b' is declared here. + + a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. + ~ +!!! error TS2339: Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. + b.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. + ~ +!!! error TS2339: Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. + + interface Foo { + a: Required; + } + const aa: Foo<{ a?: 1; x: 1 }> = { a: { a: 1, x: 1 } }; + const bb: Foo<{ b?: 1; x: 1 }> = { a: { b: 1, x: 1 } }; + export let AA = aa; + export let BB = bb; + AA = bb; // Should Error + ~~ +!!! error TS2322: Type 'Foo<{ b?: 1; x: 1; }>' is not assignable to type 'Foo<{ a?: 1; x: 1; }>'. +!!! error TS2322: Types of property 'a' are incompatible. +!!! error TS2322: Property 'a' is missing in type 'Required<{ b?: 1; x: 1; }>' but required in type 'Required<{ a?: 1; x: 1; }>'. +!!! related TS2728 tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts:14:17: 'a' is declared here. + BB = aa; // Should Error + ~~ +!!! error TS2322: Type 'Foo<{ a?: 1; x: 1; }>' is not assignable to type 'Foo<{ b?: 1; x: 1; }>'. +!!! error TS2322: Types of property 'a' are incompatible. +!!! error TS2322: Property 'b' is missing in type 'Required<{ a?: 1; x: 1; }>' but required in type 'Required<{ b?: 1; x: 1; }>'. +!!! related TS2728 tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts:15:17: 'b' is declared here. + + aa.a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. + ~ +!!! error TS2339: Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. + bb.a.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. + ~ +!!! error TS2339: Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. \ No newline at end of file diff --git a/tests/baselines/reference/requiredMappedTypeModifierTrumpsVariance.js b/tests/baselines/reference/requiredMappedTypeModifierTrumpsVariance.js new file mode 100644 index 0000000000000..b84c28781ebcd --- /dev/null +++ b/tests/baselines/reference/requiredMappedTypeModifierTrumpsVariance.js @@ -0,0 +1,43 @@ +//// [requiredMappedTypeModifierTrumpsVariance.ts] +const a: Required<{ a?: 1; x: 1 }> = { a: 1, x: 1 }; +const b: Required<{ b?: 1; x: 1 }> = { b: 1, x: 1 }; +export let A = a; +export let B = b; +A = b; // Should Error +B = a; // Should Error + +a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. +b.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. + +interface Foo { + a: Required; +} +const aa: Foo<{ a?: 1; x: 1 }> = { a: { a: 1, x: 1 } }; +const bb: Foo<{ b?: 1; x: 1 }> = { a: { b: 1, x: 1 } }; +export let AA = aa; +export let BB = bb; +AA = bb; // Should Error +BB = aa; // Should Error + +aa.a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. +bb.a.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. + +//// [requiredMappedTypeModifierTrumpsVariance.js] +"use strict"; +exports.__esModule = true; +var a = { a: 1, x: 1 }; +var b = { b: 1, x: 1 }; +exports.A = a; +exports.B = b; +exports.A = b; // Should Error +exports.B = a; // Should Error +a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. +b.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. +var aa = { a: { a: 1, x: 1 } }; +var bb = { a: { b: 1, x: 1 } }; +exports.AA = aa; +exports.BB = bb; +exports.AA = bb; // Should Error +exports.BB = aa; // Should Error +aa.a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. +bb.a.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. diff --git a/tests/baselines/reference/requiredMappedTypeModifierTrumpsVariance.symbols b/tests/baselines/reference/requiredMappedTypeModifierTrumpsVariance.symbols new file mode 100644 index 0000000000000..726e89040f2ec --- /dev/null +++ b/tests/baselines/reference/requiredMappedTypeModifierTrumpsVariance.symbols @@ -0,0 +1,92 @@ +=== tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts === +const a: Required<{ a?: 1; x: 1 }> = { a: 1, x: 1 }; +>a : Symbol(a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 0, 5)) +>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 0, 19)) +>x : Symbol(x, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 0, 26)) +>a : Symbol(a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 0, 38)) +>x : Symbol(x, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 0, 44)) + +const b: Required<{ b?: 1; x: 1 }> = { b: 1, x: 1 }; +>b : Symbol(b, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 1, 5)) +>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 1, 19)) +>x : Symbol(x, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 1, 26)) +>b : Symbol(b, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 1, 38)) +>x : Symbol(x, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 1, 44)) + +export let A = a; +>A : Symbol(A, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 2, 10)) +>a : Symbol(a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 0, 5)) + +export let B = b; +>B : Symbol(B, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 3, 10)) +>b : Symbol(b, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 1, 5)) + +A = b; // Should Error +>A : Symbol(A, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 2, 10)) +>b : Symbol(b, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 1, 5)) + +B = a; // Should Error +>B : Symbol(B, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 3, 10)) +>a : Symbol(a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 0, 5)) + +a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. +>a : Symbol(a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 0, 5)) + +b.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. +>b : Symbol(b, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 1, 5)) + +interface Foo { +>Foo : Symbol(Foo, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 8, 4)) +>T : Symbol(T, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 10, 14)) + + a: Required; +>a : Symbol(Foo.a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 10, 18)) +>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 10, 14)) +} +const aa: Foo<{ a?: 1; x: 1 }> = { a: { a: 1, x: 1 } }; +>aa : Symbol(aa, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 13, 5)) +>Foo : Symbol(Foo, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 8, 4)) +>a : Symbol(a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 13, 15)) +>x : Symbol(x, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 13, 22)) +>a : Symbol(a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 13, 34)) +>a : Symbol(a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 13, 39)) +>x : Symbol(x, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 13, 45)) + +const bb: Foo<{ b?: 1; x: 1 }> = { a: { b: 1, x: 1 } }; +>bb : Symbol(bb, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 14, 5)) +>Foo : Symbol(Foo, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 8, 4)) +>b : Symbol(b, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 14, 15)) +>x : Symbol(x, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 14, 22)) +>a : Symbol(a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 14, 34)) +>b : Symbol(b, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 14, 39)) +>x : Symbol(x, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 14, 45)) + +export let AA = aa; +>AA : Symbol(AA, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 15, 10)) +>aa : Symbol(aa, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 13, 5)) + +export let BB = bb; +>BB : Symbol(BB, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 16, 10)) +>bb : Symbol(bb, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 14, 5)) + +AA = bb; // Should Error +>AA : Symbol(AA, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 15, 10)) +>bb : Symbol(bb, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 14, 5)) + +BB = aa; // Should Error +>BB : Symbol(BB, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 16, 10)) +>aa : Symbol(aa, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 13, 5)) + +aa.a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. +>aa.a : Symbol(Foo.a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 10, 18)) +>aa : Symbol(aa, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 13, 5)) +>a : Symbol(Foo.a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 10, 18)) + +bb.a.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. +>bb.a : Symbol(Foo.a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 10, 18)) +>bb : Symbol(bb, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 14, 5)) +>a : Symbol(Foo.a, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 10, 18)) + diff --git a/tests/baselines/reference/requiredMappedTypeModifierTrumpsVariance.types b/tests/baselines/reference/requiredMappedTypeModifierTrumpsVariance.types new file mode 100644 index 0000000000000..f9d482c8fc3dd --- /dev/null +++ b/tests/baselines/reference/requiredMappedTypeModifierTrumpsVariance.types @@ -0,0 +1,109 @@ +=== tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts === +const a: Required<{ a?: 1; x: 1 }> = { a: 1, x: 1 }; +>a : Required<{ a?: 1; x: 1; }> +>a : 1 +>x : 1 +>{ a: 1, x: 1 } : { a: 1; x: 1; } +>a : 1 +>1 : 1 +>x : 1 +>1 : 1 + +const b: Required<{ b?: 1; x: 1 }> = { b: 1, x: 1 }; +>b : Required<{ b?: 1; x: 1; }> +>b : 1 +>x : 1 +>{ b: 1, x: 1 } : { b: 1; x: 1; } +>b : 1 +>1 : 1 +>x : 1 +>1 : 1 + +export let A = a; +>A : Required<{ a?: 1; x: 1; }> +>a : Required<{ a?: 1; x: 1; }> + +export let B = b; +>B : Required<{ b?: 1; x: 1; }> +>b : Required<{ b?: 1; x: 1; }> + +A = b; // Should Error +>A = b : Required<{ b?: 1; x: 1; }> +>A : Required<{ a?: 1; x: 1; }> +>b : Required<{ b?: 1; x: 1; }> + +B = a; // Should Error +>B = a : Required<{ a?: 1; x: 1; }> +>B : Required<{ b?: 1; x: 1; }> +>a : Required<{ a?: 1; x: 1; }> + +a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. +>a.b : any +>a : Required<{ a?: 1; x: 1; }> +>b : any + +b.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. +>b.a : any +>b : Required<{ b?: 1; x: 1; }> +>a : any + +interface Foo { + a: Required; +>a : Required +} +const aa: Foo<{ a?: 1; x: 1 }> = { a: { a: 1, x: 1 } }; +>aa : Foo<{ a?: 1; x: 1; }> +>a : 1 +>x : 1 +>{ a: { a: 1, x: 1 } } : { a: { a: 1; x: 1; }; } +>a : { a: 1; x: 1; } +>{ a: 1, x: 1 } : { a: 1; x: 1; } +>a : 1 +>1 : 1 +>x : 1 +>1 : 1 + +const bb: Foo<{ b?: 1; x: 1 }> = { a: { b: 1, x: 1 } }; +>bb : Foo<{ b?: 1; x: 1; }> +>b : 1 +>x : 1 +>{ a: { b: 1, x: 1 } } : { a: { b: 1; x: 1; }; } +>a : { b: 1; x: 1; } +>{ b: 1, x: 1 } : { b: 1; x: 1; } +>b : 1 +>1 : 1 +>x : 1 +>1 : 1 + +export let AA = aa; +>AA : Foo<{ a?: 1; x: 1; }> +>aa : Foo<{ a?: 1; x: 1; }> + +export let BB = bb; +>BB : Foo<{ b?: 1; x: 1; }> +>bb : Foo<{ b?: 1; x: 1; }> + +AA = bb; // Should Error +>AA = bb : Foo<{ b?: 1; x: 1; }> +>AA : Foo<{ a?: 1; x: 1; }> +>bb : Foo<{ b?: 1; x: 1; }> + +BB = aa; // Should Error +>BB = aa : Foo<{ a?: 1; x: 1; }> +>BB : Foo<{ b?: 1; x: 1; }> +>aa : Foo<{ a?: 1; x: 1; }> + +aa.a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. +>aa.a.b : any +>aa.a : Required<{ a?: 1; x: 1; }> +>aa : Foo<{ a?: 1; x: 1; }> +>a : Required<{ a?: 1; x: 1; }> +>b : any + +bb.a.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. +>bb.a.a : any +>bb.a : Required<{ b?: 1; x: 1; }> +>bb : Foo<{ b?: 1; x: 1; }> +>a : Required<{ b?: 1; x: 1; }> +>a : any + diff --git a/tests/baselines/reference/strictFunctionTypesErrors.errors.txt b/tests/baselines/reference/strictFunctionTypesErrors.errors.txt index d24b88a7a94cf..3ff04c44fb75b 100644 --- a/tests/baselines/reference/strictFunctionTypesErrors.errors.txt +++ b/tests/baselines/reference/strictFunctionTypesErrors.errors.txt @@ -62,9 +62,13 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(84,1): error TS2322: Type 'Fun tests/cases/compiler/strictFunctionTypesErrors.ts(111,1): error TS2322: Type 'Comparer2' is not assignable to type 'Comparer2'. Property 'dog' is missing in type 'Animal' but required in type 'Dog'. tests/cases/compiler/strictFunctionTypesErrors.ts(126,1): error TS2322: Type 'Crate' is not assignable to type 'Crate'. - Type 'Animal' is not assignable to type 'Dog'. + Types of property 'onSetItem' are incompatible. + Type '(item: Dog) => void' is not assignable to type '(item: Animal) => void'. + Types of parameters 'item' and 'item' are incompatible. + Type 'Animal' is not assignable to type 'Dog'. tests/cases/compiler/strictFunctionTypesErrors.ts(127,1): error TS2322: Type 'Crate' is not assignable to type 'Crate'. - Type 'Animal' is not assignable to type 'Dog'. + Types of property 'item' are incompatible. + Type 'Animal' is not assignable to type 'Dog'. tests/cases/compiler/strictFunctionTypesErrors.ts(133,1): error TS2322: Type '(f: (x: Dog) => Dog) => void' is not assignable to type '(f: (x: Animal) => Animal) => void'. Types of parameters 'f' and 'f' are incompatible. Type 'Animal' is not assignable to type 'Dog'. @@ -304,11 +308,15 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(c animalCrate = dogCrate; // Error ~~~~~~~~~~~ !!! error TS2322: Type 'Crate' is not assignable to type 'Crate'. -!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. +!!! error TS2322: Types of property 'onSetItem' are incompatible. +!!! error TS2322: Type '(item: Dog) => void' is not assignable to type '(item: Animal) => void'. +!!! error TS2322: Types of parameters 'item' and 'item' are incompatible. +!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. dogCrate = animalCrate; // Error ~~~~~~~~ !!! error TS2322: Type 'Crate' is not assignable to type 'Crate'. -!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. +!!! error TS2322: Types of property 'item' are incompatible. +!!! error TS2322: Type 'Animal' is not assignable to type 'Dog'. // Verify that callback parameters are strictly checked diff --git a/tests/baselines/reference/thisConditionalOnMethodReturnOfGenericInstance.js b/tests/baselines/reference/thisConditionalOnMethodReturnOfGenericInstance.js new file mode 100644 index 0000000000000..c903864eb672a --- /dev/null +++ b/tests/baselines/reference/thisConditionalOnMethodReturnOfGenericInstance.js @@ -0,0 +1,59 @@ +//// [thisConditionalOnMethodReturnOfGenericInstance.ts] +class A { + unmeasurableUsage!: {[K in keyof T]-?: T[K]}; +} + +class B extends A { + method(): string | (this extends C ? undefined : null) { + return ""; + } +} + +class C extends B { + marker!: string; +} + +const x = new C<{}>(); + +const y = x.method(); // usage flags `method` in `B` as circular and marks `y` as the error-any type + + +//// [thisConditionalOnMethodReturnOfGenericInstance.js] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var A = /** @class */ (function () { + function A() { + } + return A; +}()); +var B = /** @class */ (function (_super) { + __extends(B, _super); + function B() { + return _super !== null && _super.apply(this, arguments) || this; + } + B.prototype.method = function () { + return ""; + }; + return B; +}(A)); +var C = /** @class */ (function (_super) { + __extends(C, _super); + function C() { + return _super !== null && _super.apply(this, arguments) || this; + } + return C; +}(B)); +var x = new C(); +var y = x.method(); // usage flags `method` in `B` as circular and marks `y` as the error-any type diff --git a/tests/baselines/reference/thisConditionalOnMethodReturnOfGenericInstance.symbols b/tests/baselines/reference/thisConditionalOnMethodReturnOfGenericInstance.symbols new file mode 100644 index 0000000000000..ca81357af143d --- /dev/null +++ b/tests/baselines/reference/thisConditionalOnMethodReturnOfGenericInstance.symbols @@ -0,0 +1,47 @@ +=== tests/cases/compiler/thisConditionalOnMethodReturnOfGenericInstance.ts === +class A { +>A : Symbol(A, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 0, 0)) +>T : Symbol(T, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 0, 8)) + + unmeasurableUsage!: {[K in keyof T]-?: T[K]}; +>unmeasurableUsage : Symbol(A.unmeasurableUsage, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 0, 12)) +>K : Symbol(K, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 1, 26)) +>T : Symbol(T, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 0, 8)) +>T : Symbol(T, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 0, 8)) +>K : Symbol(K, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 1, 26)) +} + +class B extends A { +>B : Symbol(B, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 2, 1)) +>T : Symbol(T, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 4, 8)) +>A : Symbol(A, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 0, 0)) +>T : Symbol(T, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 4, 8)) + + method(): string | (this extends C ? undefined : null) { +>method : Symbol(B.method, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 4, 25)) +>C : Symbol(C, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 8, 1)) + + return ""; + } +} + +class C extends B { +>C : Symbol(C, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 8, 1)) +>T : Symbol(T, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 10, 8)) +>B : Symbol(B, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 2, 1)) +>T : Symbol(T, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 10, 8)) + + marker!: string; +>marker : Symbol(C.marker, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 10, 31)) +} + +const x = new C<{}>(); +>x : Symbol(x, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 14, 5)) +>C : Symbol(C, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 8, 1)) + +const y = x.method(); // usage flags `method` in `B` as circular and marks `y` as the error-any type +>y : Symbol(y, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 16, 5)) +>x.method : Symbol(B.method, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 4, 25)) +>x : Symbol(x, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 14, 5)) +>method : Symbol(B.method, Decl(thisConditionalOnMethodReturnOfGenericInstance.ts, 4, 25)) + diff --git a/tests/baselines/reference/thisConditionalOnMethodReturnOfGenericInstance.types b/tests/baselines/reference/thisConditionalOnMethodReturnOfGenericInstance.types new file mode 100644 index 0000000000000..8ec248f9d536a --- /dev/null +++ b/tests/baselines/reference/thisConditionalOnMethodReturnOfGenericInstance.types @@ -0,0 +1,41 @@ +=== tests/cases/compiler/thisConditionalOnMethodReturnOfGenericInstance.ts === +class A { +>A : A + + unmeasurableUsage!: {[K in keyof T]-?: T[K]}; +>unmeasurableUsage : { [K in keyof T]-?: T[K]; } +} + +class B extends A { +>B : B +>A : A + + method(): string | (this extends C ? undefined : null) { +>method : () => string | (this extends C ? undefined : null) +>null : null + + return ""; +>"" : "" + } +} + +class C extends B { +>C : C +>B : B + + marker!: string; +>marker : string +} + +const x = new C<{}>(); +>x : C<{}> +>new C<{}>() : C<{}> +>C : typeof C + +const y = x.method(); // usage flags `method` in `B` as circular and marks `y` as the error-any type +>y : string | undefined +>x.method() : string | undefined +>x.method : () => string | undefined +>x : C<{}> +>method : () => string | undefined + diff --git a/tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts b/tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts new file mode 100644 index 0000000000000..e21bc2d72fd2d --- /dev/null +++ b/tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts @@ -0,0 +1,39 @@ +// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being +// by incorrect variance-based relationships +// Ref: https://github.com/Microsoft/TypeScript/issues/29698 + +type Record2 = { + [P in K]: T; +}; + +function defaultRecord(x: Record<'a', string>, y: Record) { + x = y; // no error, but error expected. +} + +function customRecord(x: Record2<'a', string>, y: Record2) { + x = y; // no error, but error expected. +} + +function mixed1(x: Record2<'a', string>, y: Record) { + x = y; // error +} + +function mixed2(x: Record<'a', string>, y: Record2) { + x = y; // error +} + +function defaultRecord2(x: Record<'a', T>, y: Record) { + x = y; // no error, but error expected. +} + +function customRecord2(x: Record2<'a', T>, y: Record2) { + x = y; // no error, but error expected. +} + +function mixed3(x: Record2<'a', T>, y: Record) { + x = y; // error +} + +function mixed4(x: Record<'a', T>, y: Record2) { + x = y; // error +} diff --git a/tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts b/tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts new file mode 100644 index 0000000000000..b2017a8758101 --- /dev/null +++ b/tests/cases/compiler/requiredMappedTypeModifierTrumpsVariance.ts @@ -0,0 +1,22 @@ +const a: Required<{ a?: 1; x: 1 }> = { a: 1, x: 1 }; +const b: Required<{ b?: 1; x: 1 }> = { b: 1, x: 1 }; +export let A = a; +export let B = b; +A = b; // Should Error +B = a; // Should Error + +a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. +b.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. + +interface Foo { + a: Required; +} +const aa: Foo<{ a?: 1; x: 1 }> = { a: { a: 1, x: 1 } }; +const bb: Foo<{ b?: 1; x: 1 }> = { a: { b: 1, x: 1 } }; +export let AA = aa; +export let BB = bb; +AA = bb; // Should Error +BB = aa; // Should Error + +aa.a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'. +bb.a.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'. \ No newline at end of file diff --git a/tests/cases/compiler/thisConditionalOnMethodReturnOfGenericInstance.ts b/tests/cases/compiler/thisConditionalOnMethodReturnOfGenericInstance.ts new file mode 100644 index 0000000000000..a0264e90f4974 --- /dev/null +++ b/tests/cases/compiler/thisConditionalOnMethodReturnOfGenericInstance.ts @@ -0,0 +1,18 @@ +// @strict: true +class A { + unmeasurableUsage!: {[K in keyof T]-?: T[K]}; +} + +class B extends A { + method(): string | (this extends C ? undefined : null) { + return ""; + } +} + +class C extends B { + marker!: string; +} + +const x = new C<{}>(); + +const y = x.method(); // usage flags `method` in `B` as circular and marks `y` as the error-any type