mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-04-17 01:49:41 -05:00
Add unmeasurable variance kind for marking types whose variance result is unreliable (#30416)
* Add unmeasurable variance kind for marking types whose variance result is unreliable
* Remove now-unneeded nongeneric checks
* Add rule allowing `Readonly<any>` to be `any` instead of `{readonly [index: string]: any}`
* All Unmeasurable variances to still shortcut structural comparisons in some cases
* Separate unmeasurable from unreliable to reduce the impact of this change, for now
* Fix lint
* Remove Readonly<any> -> any callout
* Add fix for circularity error triggered by deep signature return type comparisons with `this` types
This commit is contained in:
@@ -678,6 +678,7 @@ namespace ts {
|
||||
|
||||
let _jsxNamespace: __String;
|
||||
let _jsxFactoryEntity: EntityName | undefined;
|
||||
let outofbandVarianceMarkerHandler: ((onlyUnreliable: boolean) => void) | undefined;
|
||||
|
||||
const subtypeRelation = createMap<RelationComparisonResult>();
|
||||
const assignableRelation = createMap<RelationComparisonResult>();
|
||||
@@ -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<Type> = emptyArray, targets: ReadonlyArray<Type> = emptyArray, variances: ReadonlyArray<Variance> = emptyArray, reportErrors: boolean): Ternary {
|
||||
function typeArgumentsRelatedTo(sources: ReadonlyArray<Type> = emptyArray, targets: ReadonlyArray<Type> = emptyArray, variances: ReadonlyArray<VarianceFlags> = 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<Type> | undefined, targetTypeArguments: ReadonlyArray<Type> | undefined, variances: Variance[]) {
|
||||
function relateVariances(sourceTypeArguments: ReadonlyArray<Type> | undefined, targetTypeArguments: ReadonlyArray<Type> | 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<TCache extends { variances?: Variance[] }>(typeParameters: ReadonlyArray<TypeParameter> = emptyArray, cache: TCache, createMarkerType: (input: TCache, param: TypeParameter, marker: Type) => Type): Variance[] {
|
||||
function getVariancesWorker<TCache extends { variances?: VarianceFlags[] }>(typeParameters: ReadonlyArray<TypeParameter> = 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<Type>, variances: Variance[]): boolean {
|
||||
function hasCovariantVoidArgument(typeArguments: ReadonlyArray<Type>, 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((<TypeReference>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 {
|
||||
|
||||
@@ -3735,7 +3735,7 @@ namespace ts {
|
||||
specifierCache?: Map<string>; // 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<Symbol[]>; // 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<TypeReference>; // Generic instantiation cache
|
||||
/* @internal */
|
||||
variances?: Variance[]; // Variance of each type parameter
|
||||
variances?: VarianceFlags[]; // Variance of each type parameter
|
||||
}
|
||||
|
||||
export interface TupleType extends GenericType {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
tests/cases/compiler/checkInfiniteExpansionTermination.ts(16,1): error TS2322: Type 'ISubject<Bar>' is not assignable to type 'IObservable<Foo>'.
|
||||
Types of property 'n' are incompatible.
|
||||
Type 'IObservable<Bar[]>' is not assignable to type 'IObservable<Foo[]>'.
|
||||
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<T> {
|
||||
n: IObservable<T[]>; // Needed, must be T[]
|
||||
}
|
||||
|
||||
// Needed
|
||||
interface ISubject<T> extends IObservable<T> { }
|
||||
|
||||
interface Foo { x }
|
||||
interface Bar { y }
|
||||
|
||||
var values: IObservable<Foo>;
|
||||
var values2: ISubject<Bar>;
|
||||
values = values2;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'ISubject<Bar>' is not assignable to type 'IObservable<Foo>'.
|
||||
!!! error TS2322: Types of property 'n' are incompatible.
|
||||
!!! error TS2322: Type 'IObservable<Bar[]>' is not assignable to type 'IObservable<Foo[]>'.
|
||||
!!! 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.
|
||||
|
||||
@@ -19,12 +19,8 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(104,5): error TS2
|
||||
'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>' 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<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>' is not assignable to type 'Pick<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>'.
|
||||
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<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>' is not assignable to type 'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>'.
|
||||
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<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>' is not assignable to type 'Pick<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>'.
|
||||
!!! 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<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>' is not assignable to type 'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>'.
|
||||
!!! 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<T>(x: keyof T, y: FunctionPropertyNames<T>, z: NonFunctionPropertyNames<T>) {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(18,5): error TS2741: Property 'a' is missing in type 'Record<string, string>' but required in type 'Record2<"a", string>'.
|
||||
tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(22,5): error TS2741: Property 'a' is missing in type 'Record2<string, string>' but required in type 'Record<"a", string>'.
|
||||
tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(34,5): error TS2741: Property 'a' is missing in type 'Record<string, T>' but required in type 'Record2<"a", T>'.
|
||||
tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(38,5): error TS2741: Property 'a' is missing in type 'Record2<string, T>' 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<K extends keyof any, T> = {
|
||||
[P in K]: T;
|
||||
};
|
||||
|
||||
function defaultRecord(x: Record<'a', string>, y: Record<string, string>) {
|
||||
x = y; // no error, but error expected.
|
||||
}
|
||||
|
||||
function customRecord(x: Record2<'a', string>, y: Record2<string, string>) {
|
||||
x = y; // no error, but error expected.
|
||||
}
|
||||
|
||||
function mixed1(x: Record2<'a', string>, y: Record<string, string>) {
|
||||
x = y; // error
|
||||
~
|
||||
!!! error TS2741: Property 'a' is missing in type 'Record<string, string>' but required in type 'Record2<"a", string>'.
|
||||
}
|
||||
|
||||
function mixed2(x: Record<'a', string>, y: Record2<string, string>) {
|
||||
x = y; // error
|
||||
~
|
||||
!!! error TS2741: Property 'a' is missing in type 'Record2<string, string>' but required in type 'Record<"a", string>'.
|
||||
}
|
||||
|
||||
function defaultRecord2<T>(x: Record<'a', T>, y: Record<string, T>) {
|
||||
x = y; // no error, but error expected.
|
||||
}
|
||||
|
||||
function customRecord2<T>(x: Record2<'a', T>, y: Record2<string, T>) {
|
||||
x = y; // no error, but error expected.
|
||||
}
|
||||
|
||||
function mixed3<T>(x: Record2<'a', T>, y: Record<string, T>) {
|
||||
x = y; // error
|
||||
~
|
||||
!!! error TS2741: Property 'a' is missing in type 'Record<string, T>' but required in type 'Record2<"a", T>'.
|
||||
}
|
||||
|
||||
function mixed4<T>(x: Record<'a', T>, y: Record2<string, T>) {
|
||||
x = y; // error
|
||||
~
|
||||
!!! error TS2741: Property 'a' is missing in type 'Record2<string, T>' but required in type 'Record<"a", T>'.
|
||||
}
|
||||
|
||||
@@ -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<K extends keyof any, T> = {
|
||||
[P in K]: T;
|
||||
};
|
||||
|
||||
function defaultRecord(x: Record<'a', string>, y: Record<string, string>) {
|
||||
x = y; // no error, but error expected.
|
||||
}
|
||||
|
||||
function customRecord(x: Record2<'a', string>, y: Record2<string, string>) {
|
||||
x = y; // no error, but error expected.
|
||||
}
|
||||
|
||||
function mixed1(x: Record2<'a', string>, y: Record<string, string>) {
|
||||
x = y; // error
|
||||
}
|
||||
|
||||
function mixed2(x: Record<'a', string>, y: Record2<string, string>) {
|
||||
x = y; // error
|
||||
}
|
||||
|
||||
function defaultRecord2<T>(x: Record<'a', T>, y: Record<string, T>) {
|
||||
x = y; // no error, but error expected.
|
||||
}
|
||||
|
||||
function customRecord2<T>(x: Record2<'a', T>, y: Record2<string, T>) {
|
||||
x = y; // no error, but error expected.
|
||||
}
|
||||
|
||||
function mixed3<T>(x: Record2<'a', T>, y: Record<string, T>) {
|
||||
x = y; // error
|
||||
}
|
||||
|
||||
function mixed4<T>(x: Record<'a', T>, y: Record2<string, T>) {
|
||||
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
|
||||
}
|
||||
@@ -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<K extends keyof any, T> = {
|
||||
>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<string, string>) {
|
||||
>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<string, string>) {
|
||||
>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<string, string>) {
|
||||
>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<string, string>) {
|
||||
>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<T>(x: Record<'a', T>, y: Record<string, T>) {
|
||||
>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<T>(x: Record2<'a', T>, y: Record2<string, T>) {
|
||||
>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<T>(x: Record2<'a', T>, y: Record<string, T>) {
|
||||
>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<T>(x: Record<'a', T>, y: Record2<string, T>) {
|
||||
>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))
|
||||
}
|
||||
|
||||
@@ -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<K extends keyof any, T> = {
|
||||
>Record2 : Record2<K, T>
|
||||
|
||||
[P in K]: T;
|
||||
};
|
||||
|
||||
function defaultRecord(x: Record<'a', string>, y: Record<string, string>) {
|
||||
>defaultRecord : (x: Record<"a", string>, y: Record<string, string>) => void
|
||||
>x : Record<"a", string>
|
||||
>y : Record<string, string>
|
||||
|
||||
x = y; // no error, but error expected.
|
||||
>x = y : Record<string, string>
|
||||
>x : Record<"a", string>
|
||||
>y : Record<string, string>
|
||||
}
|
||||
|
||||
function customRecord(x: Record2<'a', string>, y: Record2<string, string>) {
|
||||
>customRecord : (x: Record2<"a", string>, y: Record2<string, string>) => void
|
||||
>x : Record2<"a", string>
|
||||
>y : Record2<string, string>
|
||||
|
||||
x = y; // no error, but error expected.
|
||||
>x = y : Record2<string, string>
|
||||
>x : Record2<"a", string>
|
||||
>y : Record2<string, string>
|
||||
}
|
||||
|
||||
function mixed1(x: Record2<'a', string>, y: Record<string, string>) {
|
||||
>mixed1 : (x: Record2<"a", string>, y: Record<string, string>) => void
|
||||
>x : Record2<"a", string>
|
||||
>y : Record<string, string>
|
||||
|
||||
x = y; // error
|
||||
>x = y : Record<string, string>
|
||||
>x : Record2<"a", string>
|
||||
>y : Record<string, string>
|
||||
}
|
||||
|
||||
function mixed2(x: Record<'a', string>, y: Record2<string, string>) {
|
||||
>mixed2 : (x: Record<"a", string>, y: Record2<string, string>) => void
|
||||
>x : Record<"a", string>
|
||||
>y : Record2<string, string>
|
||||
|
||||
x = y; // error
|
||||
>x = y : Record2<string, string>
|
||||
>x : Record<"a", string>
|
||||
>y : Record2<string, string>
|
||||
}
|
||||
|
||||
function defaultRecord2<T>(x: Record<'a', T>, y: Record<string, T>) {
|
||||
>defaultRecord2 : <T>(x: Record<"a", T>, y: Record<string, T>) => void
|
||||
>x : Record<"a", T>
|
||||
>y : Record<string, T>
|
||||
|
||||
x = y; // no error, but error expected.
|
||||
>x = y : Record<string, T>
|
||||
>x : Record<"a", T>
|
||||
>y : Record<string, T>
|
||||
}
|
||||
|
||||
function customRecord2<T>(x: Record2<'a', T>, y: Record2<string, T>) {
|
||||
>customRecord2 : <T>(x: Record2<"a", T>, y: Record2<string, T>) => void
|
||||
>x : Record2<"a", T>
|
||||
>y : Record2<string, T>
|
||||
|
||||
x = y; // no error, but error expected.
|
||||
>x = y : Record2<string, T>
|
||||
>x : Record2<"a", T>
|
||||
>y : Record2<string, T>
|
||||
}
|
||||
|
||||
function mixed3<T>(x: Record2<'a', T>, y: Record<string, T>) {
|
||||
>mixed3 : <T>(x: Record2<"a", T>, y: Record<string, T>) => void
|
||||
>x : Record2<"a", T>
|
||||
>y : Record<string, T>
|
||||
|
||||
x = y; // error
|
||||
>x = y : Record<string, T>
|
||||
>x : Record2<"a", T>
|
||||
>y : Record<string, T>
|
||||
}
|
||||
|
||||
function mixed4<T>(x: Record<'a', T>, y: Record2<string, T>) {
|
||||
>mixed4 : <T>(x: Record<"a", T>, y: Record2<string, T>) => void
|
||||
>x : Record<"a", T>
|
||||
>y : Record2<string, T>
|
||||
|
||||
x = y; // error
|
||||
>x = y : Record2<string, T>
|
||||
>x : Record<"a", T>
|
||||
>y : Record2<string, T>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
tests/cases/compiler/invariantGenericErrorElaboration.ts(3,7): error TS2322: Type 'Num' is not assignable to type 'Runtype<any>'.
|
||||
Types of property 'constraint' are incompatible.
|
||||
Type 'Constraint<Num>' is not assignable to type 'Constraint<Runtype<any>>'.
|
||||
Types of property 'constraint' are incompatible.
|
||||
Type 'Constraint<Constraint<Num>>' is not assignable to type 'Constraint<Constraint<Runtype<any>>>'.
|
||||
Types of property 'constraint' are incompatible.
|
||||
Type 'Constraint<Constraint<Constraint<Num>>>' is not assignable to type 'Constraint<Constraint<Constraint<Runtype<any>>>>'.
|
||||
Type 'Constraint<Constraint<Runtype<any>>>' is not assignable to type 'Constraint<Constraint<Num>>'.
|
||||
Types of property 'underlying' are incompatible.
|
||||
Type 'Constraint<Runtype<any>>' is not assignable to type 'Constraint<Num>'.
|
||||
tests/cases/compiler/invariantGenericErrorElaboration.ts(4,19): error TS2322: Type 'Num' is not assignable to type 'Runtype<any>'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/invariantGenericErrorElaboration.ts (2 errors) ====
|
||||
// Repro from #19746
|
||||
|
||||
const wat: Runtype<any> = Num;
|
||||
~~~
|
||||
!!! error TS2322: Type 'Num' is not assignable to type 'Runtype<any>'.
|
||||
!!! error TS2322: Types of property 'constraint' are incompatible.
|
||||
!!! error TS2322: Type 'Constraint<Num>' is not assignable to type 'Constraint<Runtype<any>>'.
|
||||
!!! error TS2322: Types of property 'constraint' are incompatible.
|
||||
!!! error TS2322: Type 'Constraint<Constraint<Num>>' is not assignable to type 'Constraint<Constraint<Runtype<any>>>'.
|
||||
!!! error TS2322: Types of property 'constraint' are incompatible.
|
||||
!!! error TS2322: Type 'Constraint<Constraint<Constraint<Num>>>' is not assignable to type 'Constraint<Constraint<Constraint<Runtype<any>>>>'.
|
||||
!!! error TS2322: Type 'Constraint<Constraint<Runtype<any>>>' is not assignable to type 'Constraint<Constraint<Num>>'.
|
||||
!!! error TS2322: Types of property 'underlying' are incompatible.
|
||||
!!! error TS2322: Type 'Constraint<Runtype<any>>' is not assignable to type 'Constraint<Num>'.
|
||||
!!! 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<any>'.
|
||||
!!! related TS6501 tests/cases/compiler/invariantGenericErrorElaboration.ts:17:34: The expected type comes from this index signature.
|
||||
|
||||
interface Runtype<A> {
|
||||
constraint: Constraint<this>
|
||||
witness: A
|
||||
}
|
||||
|
||||
interface Num extends Runtype<number> {
|
||||
tag: 'number'
|
||||
}
|
||||
declare const Num: Num
|
||||
|
||||
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
|
||||
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
|
||||
|
||||
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
|
||||
underlying: A,
|
||||
check: (x: A['witness']) => void,
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ const wat: Runtype<any> = 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 : <O extends { [_: string]: Runtype<any>; }>(fields: O) => Obj<O>
|
||||
>{ foo: Num } : { foo: Num; }
|
||||
>foo : Num
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
tests/cases/conformance/types/mapped/mappedTypes5.ts(6,9): error TS2322: Type 'Partial<T>' is not assignable to type 'Readonly<T>'.
|
||||
tests/cases/conformance/types/mapped/mappedTypes5.ts(8,9): error TS2322: Type 'Partial<Readonly<T>>' is not assignable to type 'Readonly<T>'.
|
||||
tests/cases/conformance/types/mapped/mappedTypes5.ts(9,9): error TS2322: Type 'Readonly<Partial<T>>' is not assignable to type 'Readonly<T>'.
|
||||
Type 'Partial<T>' is not assignable to type 'T'.
|
||||
'Partial<T>' 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<T> = rp; // Error
|
||||
~~
|
||||
!!! error TS2322: Type 'Readonly<Partial<T>>' is not assignable to type 'Readonly<T>'.
|
||||
!!! error TS2322: Type 'Partial<T>' is not assignable to type 'T'.
|
||||
!!! error TS2322: 'Partial<T>' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.
|
||||
let c1: Partial<Readonly<T>> = p;
|
||||
let c2: Partial<Readonly<T>> = r;
|
||||
let c3: Partial<Readonly<T>> = pr;
|
||||
|
||||
27
tests/baselines/reference/recursiveTypeComparison.errors.txt
Normal file
27
tests/baselines/reference/recursiveTypeComparison.errors.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
tests/cases/compiler/recursiveTypeComparison.ts(14,5): error TS2322: Type 'Observable<{}>' is not assignable to type 'Property<number>'.
|
||||
Types of property 'needThisOne' are incompatible.
|
||||
Type 'Observable<{}>' is not assignable to type 'Observable<number>'.
|
||||
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<T> {
|
||||
// This member can't be of type T, Property<T>, or Observable<anything but T>
|
||||
needThisOne: Observable<T>;
|
||||
// Add more to make it slower
|
||||
expo1: Property<T[]>; // 0.31 seconds in check
|
||||
expo2: Property<T[]>; // 3.11 seconds
|
||||
expo3: Property<T[]>; // 82.28 seconds
|
||||
}
|
||||
interface Property<T> extends Observable<T> { }
|
||||
|
||||
var p: Observable<{}>;
|
||||
var stuck: Property<number> = p;
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'Observable<{}>' is not assignable to type 'Property<number>'.
|
||||
!!! error TS2322: Types of property 'needThisOne' are incompatible.
|
||||
!!! error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable<number>'.
|
||||
!!! error TS2322: Type '{}' is not assignable to type 'number'.
|
||||
|
||||
@@ -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<T> {
|
||||
a: Required<T>;
|
||||
}
|
||||
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; }>'.
|
||||
@@ -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<T> {
|
||||
a: Required<T>;
|
||||
}
|
||||
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; }>'.
|
||||
@@ -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<T> {
|
||||
>Foo : Symbol(Foo, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 8, 4))
|
||||
>T : Symbol(T, Decl(requiredMappedTypeModifierTrumpsVariance.ts, 10, 14))
|
||||
|
||||
a: Required<T>;
|
||||
>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))
|
||||
|
||||
@@ -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<T> {
|
||||
a: Required<T>;
|
||||
>a : Required<T>
|
||||
}
|
||||
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
|
||||
|
||||
@@ -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<Dog>' is not assignable to type 'Comparer2<Animal>'.
|
||||
Property 'dog' is missing in type 'Animal' but required in type 'Dog'.
|
||||
tests/cases/compiler/strictFunctionTypesErrors.ts(126,1): error TS2322: Type 'Crate<Dog>' is not assignable to type 'Crate<Animal>'.
|
||||
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<Animal>' is not assignable to type 'Crate<Dog>'.
|
||||
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<Dog>' is not assignable to type 'Crate<Animal>'.
|
||||
!!! 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<Animal>' is not assignable to type 'Crate<Dog>'.
|
||||
!!! 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
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
//// [thisConditionalOnMethodReturnOfGenericInstance.ts]
|
||||
class A<T> {
|
||||
unmeasurableUsage!: {[K in keyof T]-?: T[K]};
|
||||
}
|
||||
|
||||
class B<T> extends A<T> {
|
||||
method(): string | (this extends C ? undefined : null) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
class C<T = any> extends B<T> {
|
||||
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
|
||||
@@ -0,0 +1,47 @@
|
||||
=== tests/cases/compiler/thisConditionalOnMethodReturnOfGenericInstance.ts ===
|
||||
class A<T> {
|
||||
>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<T> extends A<T> {
|
||||
>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<T = any> extends B<T> {
|
||||
>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))
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
=== tests/cases/compiler/thisConditionalOnMethodReturnOfGenericInstance.ts ===
|
||||
class A<T> {
|
||||
>A : A<T>
|
||||
|
||||
unmeasurableUsage!: {[K in keyof T]-?: T[K]};
|
||||
>unmeasurableUsage : { [K in keyof T]-?: T[K]; }
|
||||
}
|
||||
|
||||
class B<T> extends A<T> {
|
||||
>B : B<T>
|
||||
>A : A<T>
|
||||
|
||||
method(): string | (this extends C ? undefined : null) {
|
||||
>method : () => string | (this extends C<any> ? undefined : null)
|
||||
>null : null
|
||||
|
||||
return "";
|
||||
>"" : ""
|
||||
}
|
||||
}
|
||||
|
||||
class C<T = any> extends B<T> {
|
||||
>C : C<T>
|
||||
>B : B<T>
|
||||
|
||||
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
|
||||
|
||||
@@ -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<K extends keyof any, T> = {
|
||||
[P in K]: T;
|
||||
};
|
||||
|
||||
function defaultRecord(x: Record<'a', string>, y: Record<string, string>) {
|
||||
x = y; // no error, but error expected.
|
||||
}
|
||||
|
||||
function customRecord(x: Record2<'a', string>, y: Record2<string, string>) {
|
||||
x = y; // no error, but error expected.
|
||||
}
|
||||
|
||||
function mixed1(x: Record2<'a', string>, y: Record<string, string>) {
|
||||
x = y; // error
|
||||
}
|
||||
|
||||
function mixed2(x: Record<'a', string>, y: Record2<string, string>) {
|
||||
x = y; // error
|
||||
}
|
||||
|
||||
function defaultRecord2<T>(x: Record<'a', T>, y: Record<string, T>) {
|
||||
x = y; // no error, but error expected.
|
||||
}
|
||||
|
||||
function customRecord2<T>(x: Record2<'a', T>, y: Record2<string, T>) {
|
||||
x = y; // no error, but error expected.
|
||||
}
|
||||
|
||||
function mixed3<T>(x: Record2<'a', T>, y: Record<string, T>) {
|
||||
x = y; // error
|
||||
}
|
||||
|
||||
function mixed4<T>(x: Record<'a', T>, y: Record2<string, T>) {
|
||||
x = y; // error
|
||||
}
|
||||
@@ -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<T> {
|
||||
a: Required<T>;
|
||||
}
|
||||
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; }>'.
|
||||
@@ -0,0 +1,18 @@
|
||||
// @strict: true
|
||||
class A<T> {
|
||||
unmeasurableUsage!: {[K in keyof T]-?: T[K]};
|
||||
}
|
||||
|
||||
class B<T> extends A<T> {
|
||||
method(): string | (this extends C ? undefined : null) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
class C<T = any> extends B<T> {
|
||||
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
|
||||
Reference in New Issue
Block a user