mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-12 02:28:28 -06:00
Improve excess property checking for intersections (#32582)
* Improve excess property checking for intersections Still a draft, the implementation needs improvement * Use mutable isIntersection in checkTypeRelatedTo This makes parameter lists a lot shorter. Seems like a slight improvement, although I can revert if I change my mind. * Fix semicolon lint * Remove TODOOOO * Revert "Use mutable isIntersection in checkTypeRelatedTo" This reverts commit b8dccff2a25495867cff070b94601015e689b8ff.
This commit is contained in:
parent
d00056f096
commit
480b73915f
@ -12802,7 +12802,7 @@ namespace ts {
|
||||
isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True;
|
||||
|
||||
const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
|
||||
const isPerformingExcessPropertyChecks = (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral);
|
||||
const isPerformingExcessPropertyChecks = !isApparentIntersectionConstituent && (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral);
|
||||
if (isPerformingExcessPropertyChecks) {
|
||||
const discriminantType = target.flags & TypeFlags.Union ? findMatchingDiscriminantType(source, target as UnionType) : undefined;
|
||||
if (hasExcessProperties(<FreshObjectLiteralType>source, target, discriminantType, reportErrors)) {
|
||||
@ -12813,11 +12813,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (relation !== comparableRelation && !isApparentIntersectionConstituent &&
|
||||
const isPerformingCommonPropertyChecks = relation !== comparableRelation && !isApparentIntersectionConstituent &&
|
||||
source.flags & (TypeFlags.Primitive | TypeFlags.Object | TypeFlags.Intersection) && source !== globalObjectType &&
|
||||
target.flags & (TypeFlags.Object | TypeFlags.Intersection) && isWeakType(target) &&
|
||||
(getPropertiesOfType(source).length > 0 || typeHasCallOrConstructSignatures(source)) &&
|
||||
!hasCommonProperties(source, target, isComparingJsxAttributes)) {
|
||||
(getPropertiesOfType(source).length > 0 || typeHasCallOrConstructSignatures(source));
|
||||
if (isPerformingCommonPropertyChecks && !hasCommonProperties(source, target, isComparingJsxAttributes)) {
|
||||
if (reportErrors) {
|
||||
const calls = getSignaturesOfType(source, SignatureKind.Call);
|
||||
const constructs = getSignaturesOfType(source, SignatureKind.Construct);
|
||||
@ -12847,10 +12847,10 @@ namespace ts {
|
||||
else {
|
||||
if (target.flags & TypeFlags.Union) {
|
||||
result = typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive));
|
||||
if (result && isPerformingExcessPropertyChecks) {
|
||||
if (result && (isPerformingExcessPropertyChecks || isPerformingCommonPropertyChecks)) {
|
||||
// Validate against excess props using the original `source`
|
||||
const discriminantType = findMatchingDiscriminantType(source, target as UnionType) || filterPrimitivesIfContainsNonPrimitive(target as UnionType);
|
||||
if (!propertiesRelatedTo(source, discriminantType, reportErrors, /*excludedProperties*/ undefined)) {
|
||||
if (!propertiesRelatedTo(source, discriminantType, reportErrors, /*excludedProperties*/ undefined, isIntersectionConstituent)) {
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
@ -12858,9 +12858,9 @@ namespace ts {
|
||||
else if (target.flags & TypeFlags.Intersection) {
|
||||
isIntersectionConstituent = true; // set here to affect the following trio of checks
|
||||
result = typeRelatedToEachType(getRegularTypeOfObjectLiteral(source), target as IntersectionType, reportErrors);
|
||||
if (result && isPerformingExcessPropertyChecks) {
|
||||
if (result && (isPerformingExcessPropertyChecks || isPerformingCommonPropertyChecks)) {
|
||||
// Validate against excess props using the original `source`
|
||||
if (!propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined)) {
|
||||
if (!propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, /*isIntersectionConstituent*/ false)) {
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
@ -13186,7 +13186,7 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function typeArgumentsRelatedTo(sources: ReadonlyArray<Type> = emptyArray, targets: ReadonlyArray<Type> = emptyArray, variances: ReadonlyArray<VarianceFlags> = emptyArray, reportErrors: boolean): Ternary {
|
||||
function typeArgumentsRelatedTo(sources: ReadonlyArray<Type> = emptyArray, targets: ReadonlyArray<Type> = emptyArray, variances: ReadonlyArray<VarianceFlags> = emptyArray, reportErrors: boolean, isIntersectionConstituent: boolean): Ternary {
|
||||
if (sources.length !== targets.length && relation === identityRelation) {
|
||||
return Ternary.False;
|
||||
}
|
||||
@ -13210,10 +13210,10 @@ namespace ts {
|
||||
related = relation === identityRelation ? isRelatedTo(s, t, /*reportErrors*/ false) : compareTypesIdentical(s, t);
|
||||
}
|
||||
else if (variance === VarianceFlags.Covariant) {
|
||||
related = isRelatedTo(s, t, reportErrors);
|
||||
related = isRelatedTo(s, t, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent);
|
||||
}
|
||||
else if (variance === VarianceFlags.Contravariant) {
|
||||
related = isRelatedTo(t, s, reportErrors);
|
||||
related = isRelatedTo(t, s, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent);
|
||||
}
|
||||
else if (variance === VarianceFlags.Bivariant) {
|
||||
// In the bivariant case we first compare contravariantly without reporting
|
||||
@ -13222,16 +13222,16 @@ namespace ts {
|
||||
// which is generally easier to reason about.
|
||||
related = isRelatedTo(t, s, /*reportErrors*/ false);
|
||||
if (!related) {
|
||||
related = isRelatedTo(s, t, reportErrors);
|
||||
related = isRelatedTo(s, t, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// In the invariant case we first compare covariantly, and only when that
|
||||
// succeeds do we proceed to compare contravariantly. Thus, error elaboration
|
||||
// will typically be based on the covariant check.
|
||||
related = isRelatedTo(s, t, reportErrors);
|
||||
related = isRelatedTo(s, t, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent);
|
||||
if (related) {
|
||||
related &= isRelatedTo(t, s, reportErrors);
|
||||
related &= isRelatedTo(t, s, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent);
|
||||
}
|
||||
}
|
||||
if (!related) {
|
||||
@ -13377,7 +13377,7 @@ namespace ts {
|
||||
source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol &&
|
||||
!(source.aliasTypeArgumentsContainsMarker || target.aliasTypeArgumentsContainsMarker)) {
|
||||
const variances = getAliasVariances(source.aliasSymbol);
|
||||
const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances);
|
||||
const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances, isIntersectionConstituent);
|
||||
if (varianceResult !== undefined) {
|
||||
return varianceResult;
|
||||
}
|
||||
@ -13563,7 +13563,7 @@ namespace ts {
|
||||
// type references (which are intended by be compared structurally). Obtain the variance
|
||||
// information for the type parameters and relate the type arguments accordingly.
|
||||
const variances = getVariances((<TypeReference>source).target);
|
||||
const varianceResult = relateVariances((<TypeReference>source).typeArguments, (<TypeReference>target).typeArguments, variances);
|
||||
const varianceResult = relateVariances((<TypeReference>source).typeArguments, (<TypeReference>target).typeArguments, variances, isIntersectionConstituent);
|
||||
if (varianceResult !== undefined) {
|
||||
return varianceResult;
|
||||
}
|
||||
@ -13591,7 +13591,7 @@ namespace ts {
|
||||
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection) && target.flags & TypeFlags.Object) {
|
||||
// Report structural errors only if we haven't reported any errors yet
|
||||
const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo && !sourceIsPrimitive;
|
||||
result = propertiesRelatedTo(source, target, reportStructuralErrors, /*excludedProperties*/ undefined);
|
||||
result = propertiesRelatedTo(source, target, reportStructuralErrors, /*excludedProperties*/ undefined, isIntersectionConstituent);
|
||||
if (result) {
|
||||
result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportStructuralErrors);
|
||||
if (result) {
|
||||
@ -13627,8 +13627,8 @@ namespace ts {
|
||||
}
|
||||
return Ternary.False;
|
||||
|
||||
function relateVariances(sourceTypeArguments: ReadonlyArray<Type> | undefined, targetTypeArguments: ReadonlyArray<Type> | undefined, variances: VarianceFlags[]) {
|
||||
if (result = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors)) {
|
||||
function relateVariances(sourceTypeArguments: ReadonlyArray<Type> | undefined, targetTypeArguments: ReadonlyArray<Type> | undefined, variances: VarianceFlags[], isIntersectionConstituent: boolean) {
|
||||
if (result = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors, isIntersectionConstituent)) {
|
||||
return result;
|
||||
}
|
||||
if (some(variances, v => !!(v & VarianceFlags.AllowsStructuralFallback))) {
|
||||
@ -13756,7 +13756,7 @@ namespace ts {
|
||||
if (!targetProperty) continue outer;
|
||||
if (sourceProperty === targetProperty) continue;
|
||||
// We compare the source property to the target in the context of a single discriminant type.
|
||||
const related = propertyRelatedTo(source, target, sourceProperty, targetProperty, _ => combination[i], /*reportErrors*/ false);
|
||||
const related = propertyRelatedTo(source, target, sourceProperty, targetProperty, _ => combination[i], /*reportErrors*/ false, /*isIntersectionConstituent*/ false);
|
||||
// If the target property could not be found, or if the properties were not related,
|
||||
// then this constituent is not a match.
|
||||
if (!related) {
|
||||
@ -13775,7 +13775,7 @@ namespace ts {
|
||||
// Compare the remaining non-discriminant properties of each match.
|
||||
let result = Ternary.True;
|
||||
for (const type of matchingTypes) {
|
||||
result &= propertiesRelatedTo(source, type, /*reportErrors*/ false, excludedProperties);
|
||||
result &= propertiesRelatedTo(source, type, /*reportErrors*/ false, excludedProperties, /*isIntersectionConstituent*/ false);
|
||||
if (result) {
|
||||
result &= signaturesRelatedTo(source, type, SignatureKind.Call, /*reportStructuralErrors*/ false);
|
||||
if (result) {
|
||||
@ -13811,7 +13811,7 @@ namespace ts {
|
||||
return result || properties;
|
||||
}
|
||||
|
||||
function isPropertySymbolTypeRelated(sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean): Ternary {
|
||||
function isPropertySymbolTypeRelated(sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, isIntersectionConstituent: boolean): Ternary {
|
||||
const targetIsOptional = strictNullChecks && !!(getCheckFlags(targetProp) & CheckFlags.Partial);
|
||||
const source = getTypeOfSourceProperty(sourceProp);
|
||||
if (getCheckFlags(targetProp) & CheckFlags.DeferredType && !getSymbolLinks(targetProp).type) {
|
||||
@ -13850,11 +13850,11 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return isRelatedTo(source, addOptionality(getTypeOfSymbol(targetProp), targetIsOptional), reportErrors);
|
||||
return isRelatedTo(source, addOptionality(getTypeOfSymbol(targetProp), targetIsOptional), reportErrors, /*headMessage*/ undefined, isIntersectionConstituent);
|
||||
}
|
||||
}
|
||||
|
||||
function propertyRelatedTo(source: Type, target: Type, sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean): Ternary {
|
||||
function propertyRelatedTo(source: Type, target: Type, sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, isIntersectionConstituent: boolean): Ternary {
|
||||
const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp);
|
||||
const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp);
|
||||
if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) {
|
||||
@ -13896,7 +13896,7 @@ namespace ts {
|
||||
return Ternary.False;
|
||||
}
|
||||
// If the target comes from a partial union prop, allow `undefined` in the target type
|
||||
const related = isPropertySymbolTypeRelated(sourceProp, targetProp, getTypeOfSourceProperty, reportErrors);
|
||||
const related = isPropertySymbolTypeRelated(sourceProp, targetProp, getTypeOfSourceProperty, reportErrors, isIntersectionConstituent);
|
||||
if (!related) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp));
|
||||
@ -13921,7 +13921,7 @@ namespace ts {
|
||||
return related;
|
||||
}
|
||||
|
||||
function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean, excludedProperties: UnderscoreEscapedMap<true> | undefined): Ternary {
|
||||
function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean, excludedProperties: UnderscoreEscapedMap<true> | undefined, isIntersectionConstituent: boolean): Ternary {
|
||||
if (relation === identityRelation) {
|
||||
return propertiesIdenticalTo(source, target, excludedProperties);
|
||||
}
|
||||
@ -14008,7 +14008,7 @@ namespace ts {
|
||||
if (!(targetProp.flags & SymbolFlags.Prototype)) {
|
||||
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
|
||||
if (sourceProp && sourceProp !== targetProp) {
|
||||
const related = propertyRelatedTo(source, target, sourceProp, targetProp, getTypeOfSymbol, reportErrors);
|
||||
const related = propertyRelatedTo(source, target, sourceProp, targetProp, getTypeOfSymbol, reportErrors, isIntersectionConstituent);
|
||||
if (!related) {
|
||||
return Ternary.False;
|
||||
}
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
//// [excessPropertyCheckWithNestedArrayIntersection.ts]
|
||||
interface ValueOnlyFields {
|
||||
fields: Array<{
|
||||
value: number | null;
|
||||
}>;
|
||||
}
|
||||
interface ValueAndKeyFields {
|
||||
fields: Array<{
|
||||
key: string | null;
|
||||
value: number | null;
|
||||
}>;
|
||||
}
|
||||
interface BugRepro {
|
||||
dataType: ValueAndKeyFields & ValueOnlyFields;
|
||||
}
|
||||
const repro: BugRepro = {
|
||||
dataType: {
|
||||
fields: [{
|
||||
key: 'bla', // should be OK: Not excess
|
||||
value: null,
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [excessPropertyCheckWithNestedArrayIntersection.js]
|
||||
var repro = {
|
||||
dataType: {
|
||||
fields: [{
|
||||
key: 'bla',
|
||||
value: null
|
||||
}]
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,56 @@
|
||||
=== tests/cases/compiler/excessPropertyCheckWithNestedArrayIntersection.ts ===
|
||||
interface ValueOnlyFields {
|
||||
>ValueOnlyFields : Symbol(ValueOnlyFields, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 0, 0))
|
||||
|
||||
fields: Array<{
|
||||
>fields : Symbol(ValueOnlyFields.fields, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 0, 27))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
value: number | null;
|
||||
>value : Symbol(value, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 1, 19))
|
||||
|
||||
}>;
|
||||
}
|
||||
interface ValueAndKeyFields {
|
||||
>ValueAndKeyFields : Symbol(ValueAndKeyFields, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 4, 1))
|
||||
|
||||
fields: Array<{
|
||||
>fields : Symbol(ValueAndKeyFields.fields, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 5, 29))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
key: string | null;
|
||||
>key : Symbol(key, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 6, 19))
|
||||
|
||||
value: number | null;
|
||||
>value : Symbol(value, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 7, 27))
|
||||
|
||||
}>;
|
||||
}
|
||||
interface BugRepro {
|
||||
>BugRepro : Symbol(BugRepro, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 10, 1))
|
||||
|
||||
dataType: ValueAndKeyFields & ValueOnlyFields;
|
||||
>dataType : Symbol(BugRepro.dataType, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 11, 20))
|
||||
>ValueAndKeyFields : Symbol(ValueAndKeyFields, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 4, 1))
|
||||
>ValueOnlyFields : Symbol(ValueOnlyFields, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 0, 0))
|
||||
}
|
||||
const repro: BugRepro = {
|
||||
>repro : Symbol(repro, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 14, 5))
|
||||
>BugRepro : Symbol(BugRepro, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 10, 1))
|
||||
|
||||
dataType: {
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 14, 25))
|
||||
|
||||
fields: [{
|
||||
>fields : Symbol(fields, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 15, 13))
|
||||
|
||||
key: 'bla', // should be OK: Not excess
|
||||
>key : Symbol(key, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 16, 14))
|
||||
|
||||
value: null,
|
||||
>value : Symbol(value, Decl(excessPropertyCheckWithNestedArrayIntersection.ts, 17, 17))
|
||||
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,54 @@
|
||||
=== tests/cases/compiler/excessPropertyCheckWithNestedArrayIntersection.ts ===
|
||||
interface ValueOnlyFields {
|
||||
fields: Array<{
|
||||
>fields : { value: number; }[]
|
||||
|
||||
value: number | null;
|
||||
>value : number
|
||||
>null : null
|
||||
|
||||
}>;
|
||||
}
|
||||
interface ValueAndKeyFields {
|
||||
fields: Array<{
|
||||
>fields : { key: string; value: number; }[]
|
||||
|
||||
key: string | null;
|
||||
>key : string
|
||||
>null : null
|
||||
|
||||
value: number | null;
|
||||
>value : number
|
||||
>null : null
|
||||
|
||||
}>;
|
||||
}
|
||||
interface BugRepro {
|
||||
dataType: ValueAndKeyFields & ValueOnlyFields;
|
||||
>dataType : ValueAndKeyFields & ValueOnlyFields
|
||||
}
|
||||
const repro: BugRepro = {
|
||||
>repro : BugRepro
|
||||
>{ dataType: { fields: [{ key: 'bla', // should be OK: Not excess value: null, }], }} : { dataType: { fields: { key: string; value: null; }[]; }; }
|
||||
|
||||
dataType: {
|
||||
>dataType : { fields: { key: string; value: null; }[]; }
|
||||
>{ fields: [{ key: 'bla', // should be OK: Not excess value: null, }], } : { fields: { key: string; value: null; }[]; }
|
||||
|
||||
fields: [{
|
||||
>fields : { key: string; value: null; }[]
|
||||
>[{ key: 'bla', // should be OK: Not excess value: null, }] : { key: string; value: null; }[]
|
||||
>{ key: 'bla', // should be OK: Not excess value: null, } : { key: string; value: null; }
|
||||
|
||||
key: 'bla', // should be OK: Not excess
|
||||
>key : string
|
||||
>'bla' : "bla"
|
||||
|
||||
value: null,
|
||||
>value : null
|
||||
>null : null
|
||||
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts(70,50): erro
|
||||
~
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
!!! related TS6500 tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts:4:5: The expected type comes from property 'x' which is declared here on type 'A'
|
||||
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // should be an error
|
||||
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // error - y does not exist in type A
|
||||
~~~~
|
||||
!!! error TS2322: Type '{ x: string; y: number; }' is not assignable to type 'A'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'y' does not exist in type 'A'.
|
||||
|
||||
@ -21,7 +21,7 @@ let c: B = { a: { x: 'hello', y: 2 } }; // error - y does not exist in type A
|
||||
|
||||
let d: D = { a: { x: 'hello' }, c: 5 }; // ok
|
||||
let e: D = { a: { x: 2 }, c: 5 }; // error - types of property x are incompatible
|
||||
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // should be an error
|
||||
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // error - y does not exist in type A
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/18075
|
||||
|
||||
@ -80,7 +80,7 @@ var b = { a: { x: 2 } }; // error - types of property x are incompatible
|
||||
var c = { a: { x: 'hello', y: 2 } }; // error - y does not exist in type A
|
||||
var d = { a: { x: 'hello' }, c: 5 }; // ok
|
||||
var e = { a: { x: 2 }, c: 5 }; // error - types of property x are incompatible
|
||||
var f = { a: { x: 'hello', y: 2 }, c: 5 }; // should be an error
|
||||
var f = { a: { x: 'hello', y: 2 }, c: 5 }; // error - y does not exist in type A
|
||||
exports.photo = {
|
||||
id: 1,
|
||||
url: '',
|
||||
|
||||
@ -61,7 +61,7 @@ let e: D = { a: { x: 2 }, c: 5 }; // error - types of property x are incompatibl
|
||||
>x : Symbol(x, Decl(excessPropertyChecksWithNestedIntersections.ts, 21, 17))
|
||||
>c : Symbol(c, Decl(excessPropertyChecksWithNestedIntersections.ts, 21, 25))
|
||||
|
||||
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // should be an error
|
||||
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // error - y does not exist in type A
|
||||
>f : Symbol(f, Decl(excessPropertyChecksWithNestedIntersections.ts, 22, 3))
|
||||
>D : Symbol(D, Decl(excessPropertyChecksWithNestedIntersections.ts, 12, 1))
|
||||
>a : Symbol(a, Decl(excessPropertyChecksWithNestedIntersections.ts, 22, 12))
|
||||
|
||||
@ -65,7 +65,7 @@ let e: D = { a: { x: 2 }, c: 5 }; // error - types of property x are incompatibl
|
||||
>c : number
|
||||
>5 : 5
|
||||
|
||||
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // should be an error
|
||||
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // error - y does not exist in type A
|
||||
>f : D
|
||||
>{ a: { x: 'hello', y: 2 }, c: 5 } : { a: { x: string; y: number; }; c: number; }
|
||||
>a : { x: string; y: number; }
|
||||
|
||||
@ -5,10 +5,8 @@ tests/cases/compiler/weakType.ts(18,13): error TS2559: Type '12' has no properti
|
||||
tests/cases/compiler/weakType.ts(19,13): error TS2559: Type '"completely wrong"' has no properties in common with type 'Settings'.
|
||||
tests/cases/compiler/weakType.ts(20,13): error TS2559: Type 'false' has no properties in common with type 'Settings'.
|
||||
tests/cases/compiler/weakType.ts(37,18): error TS2559: Type '{ error?: number; }' has no properties in common with type 'ChangeOptions'.
|
||||
tests/cases/compiler/weakType.ts(62,5): error TS2322: Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak & Spoiler'.
|
||||
Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak'.
|
||||
Types of property 'properties' are incompatible.
|
||||
Type '{ wrong: string; }' has no properties in common with type '{ b?: number; }'.
|
||||
tests/cases/compiler/weakType.ts(62,5): error TS2326: Types of property 'properties' are incompatible.
|
||||
Type '{ wrong: string; }' has no properties in common with type '{ b?: number; }'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/weakType.ts (8 errors) ====
|
||||
@ -85,16 +83,14 @@ tests/cases/compiler/weakType.ts(62,5): error TS2322: Type '{ properties: { wron
|
||||
b?: number
|
||||
}
|
||||
}
|
||||
declare let unknown: {
|
||||
declare let propertiesWrong: {
|
||||
properties: {
|
||||
wrong: string
|
||||
}
|
||||
}
|
||||
let weak: Weak & Spoiler = unknown
|
||||
let weak: Weak & Spoiler = propertiesWrong
|
||||
~~~~
|
||||
!!! error TS2322: Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak & Spoiler'.
|
||||
!!! error TS2322: Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak'.
|
||||
!!! error TS2322: Types of property 'properties' are incompatible.
|
||||
!!! error TS2322: Type '{ wrong: string; }' has no properties in common with type '{ b?: number; }'.
|
||||
!!! error TS2326: Types of property 'properties' are incompatible.
|
||||
!!! error TS2326: Type '{ wrong: string; }' has no properties in common with type '{ b?: number; }'.
|
||||
|
||||
|
||||
@ -55,12 +55,12 @@ type Weak = {
|
||||
b?: number
|
||||
}
|
||||
}
|
||||
declare let unknown: {
|
||||
declare let propertiesWrong: {
|
||||
properties: {
|
||||
wrong: string
|
||||
}
|
||||
}
|
||||
let weak: Weak & Spoiler = unknown
|
||||
let weak: Weak & Spoiler = propertiesWrong
|
||||
|
||||
|
||||
|
||||
@ -89,4 +89,4 @@ var K = /** @class */ (function () {
|
||||
return K;
|
||||
}());
|
||||
var ctor = K;
|
||||
var weak = unknown;
|
||||
var weak = propertiesWrong;
|
||||
|
||||
@ -144,20 +144,20 @@ type Weak = {
|
||||
>b : Symbol(b, Decl(weakType.ts, 52, 18))
|
||||
}
|
||||
}
|
||||
declare let unknown: {
|
||||
>unknown : Symbol(unknown, Decl(weakType.ts, 56, 11))
|
||||
declare let propertiesWrong: {
|
||||
>propertiesWrong : Symbol(propertiesWrong, Decl(weakType.ts, 56, 11))
|
||||
|
||||
properties: {
|
||||
>properties : Symbol(properties, Decl(weakType.ts, 56, 22))
|
||||
>properties : Symbol(properties, Decl(weakType.ts, 56, 30))
|
||||
|
||||
wrong: string
|
||||
>wrong : Symbol(wrong, Decl(weakType.ts, 57, 17))
|
||||
}
|
||||
}
|
||||
let weak: Weak & Spoiler = unknown
|
||||
let weak: Weak & Spoiler = propertiesWrong
|
||||
>weak : Symbol(weak, Decl(weakType.ts, 61, 3))
|
||||
>Weak : Symbol(Weak, Decl(weakType.ts, 49, 32))
|
||||
>Spoiler : Symbol(Spoiler, Decl(weakType.ts, 47, 18))
|
||||
>unknown : Symbol(unknown, Decl(weakType.ts, 56, 11))
|
||||
>propertiesWrong : Symbol(propertiesWrong, Decl(weakType.ts, 56, 11))
|
||||
|
||||
|
||||
|
||||
@ -147,8 +147,8 @@ type Weak = {
|
||||
>b : number
|
||||
}
|
||||
}
|
||||
declare let unknown: {
|
||||
>unknown : { properties: { wrong: string; }; }
|
||||
declare let propertiesWrong: {
|
||||
>propertiesWrong : { properties: { wrong: string; }; }
|
||||
|
||||
properties: {
|
||||
>properties : { wrong: string; }
|
||||
@ -157,8 +157,8 @@ declare let unknown: {
|
||||
>wrong : string
|
||||
}
|
||||
}
|
||||
let weak: Weak & Spoiler = unknown
|
||||
let weak: Weak & Spoiler = propertiesWrong
|
||||
>weak : Weak & Spoiler
|
||||
>unknown : { properties: { wrong: string; }; }
|
||||
>propertiesWrong : { properties: { wrong: string; }; }
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
interface ValueOnlyFields {
|
||||
fields: Array<{
|
||||
value: number | null;
|
||||
}>;
|
||||
}
|
||||
interface ValueAndKeyFields {
|
||||
fields: Array<{
|
||||
key: string | null;
|
||||
value: number | null;
|
||||
}>;
|
||||
}
|
||||
interface BugRepro {
|
||||
dataType: ValueAndKeyFields & ValueOnlyFields;
|
||||
}
|
||||
const repro: BugRepro = {
|
||||
dataType: {
|
||||
fields: [{
|
||||
key: 'bla', // should be OK: Not excess
|
||||
value: null,
|
||||
}],
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,7 @@ let c: B = { a: { x: 'hello', y: 2 } }; // error - y does not exist in type A
|
||||
|
||||
let d: D = { a: { x: 'hello' }, c: 5 }; // ok
|
||||
let e: D = { a: { x: 2 }, c: 5 }; // error - types of property x are incompatible
|
||||
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // should be an error
|
||||
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // error - y does not exist in type A
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/18075
|
||||
|
||||
|
||||
@ -54,10 +54,10 @@ type Weak = {
|
||||
b?: number
|
||||
}
|
||||
}
|
||||
declare let unknown: {
|
||||
declare let propertiesWrong: {
|
||||
properties: {
|
||||
wrong: string
|
||||
}
|
||||
}
|
||||
let weak: Weak & Spoiler = unknown
|
||||
let weak: Weak & Spoiler = propertiesWrong
|
||||
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 1e471a007968b7490563b91ed6909ae6046f3fe8
|
||||
Subproject commit 6fae09b67ec6f7b27259a5c133a6961d05a4161b
|
||||
Loading…
x
Reference in New Issue
Block a user