From b8baf4804370a4405f7f123db5bbb4530297982b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 14 Mar 2020 09:45:05 -0700 Subject: [PATCH] Fix assignment of intersections to objects with optional properties (#37195) * Treat intersections of only objects as a single object in relations * Exclude intersections containing non-inferrable types * Accept new baselines * Update test * Accept new baselines * Add tests --- src/compiler/checker.ts | 4 +- ...ersectionsAndOptionalProperties.errors.txt | 49 ++++++++++++++ .../intersectionsAndOptionalProperties.js | 33 ++++++++++ ...intersectionsAndOptionalProperties.symbols | 64 ++++++++++++++++++ .../intersectionsAndOptionalProperties.types | 65 +++++++++++++++++++ ...ormalizedIntersectionTooComplex.errors.txt | 6 +- .../reference/propTypeValidatorInference.js | 2 +- .../propTypeValidatorInference.symbols | 44 ++++++------- .../propTypeValidatorInference.types | 4 +- .../intersectionsAndOptionalProperties.ts | 23 +++++++ .../compiler/propTypeValidatorInference.ts | 2 +- 11 files changed, 265 insertions(+), 31 deletions(-) create mode 100644 tests/baselines/reference/intersectionsAndOptionalProperties.errors.txt create mode 100644 tests/baselines/reference/intersectionsAndOptionalProperties.js create mode 100644 tests/baselines/reference/intersectionsAndOptionalProperties.symbols create mode 100644 tests/baselines/reference/intersectionsAndOptionalProperties.types create mode 100644 tests/cases/compiler/intersectionsAndOptionalProperties.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f6c4b1efc7..c89f008302 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15415,7 +15415,9 @@ namespace ts { // // - For a primitive type or type parameter (such as 'number = A & B') there is no point in // breaking the intersection apart. - result = someTypeRelatedToType(source, target, /*reportErrors*/ false, IntersectionState.Source); + if (!isNonGenericObjectType(target) || !every((source).types, t => isNonGenericObjectType(t) && !(getObjectFlags(t) & ObjectFlags.NonInferrableType))) { + result = someTypeRelatedToType(source, target, /*reportErrors*/ false, IntersectionState.Source); + } } if (!result && (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable)) { if (result = recursiveTypeRelatedTo(source, target, reportErrors, intersectionState)) { diff --git a/tests/baselines/reference/intersectionsAndOptionalProperties.errors.txt b/tests/baselines/reference/intersectionsAndOptionalProperties.errors.txt new file mode 100644 index 0000000000..bcd0a6f841 --- /dev/null +++ b/tests/baselines/reference/intersectionsAndOptionalProperties.errors.txt @@ -0,0 +1,49 @@ +tests/cases/compiler/intersectionsAndOptionalProperties.ts(5,1): error TS2322: Type '{ a: null; b: string; }' is not assignable to type '{ a?: number | undefined; b: string; }'. + Types of property 'a' are incompatible. + Type 'null' is not assignable to type 'number | undefined'. +tests/cases/compiler/intersectionsAndOptionalProperties.ts(6,1): error TS2322: Type '{ a: null; } & { b: string; }' is not assignable to type '{ a?: number | undefined; b: string; }'. + Types of property 'a' are incompatible. + Type 'null' is not assignable to type 'number | undefined'. +tests/cases/compiler/intersectionsAndOptionalProperties.ts(19,5): error TS2322: Type 'From' is not assignable to type 'To'. + Types of property 'field' are incompatible. + Type 'null' is not assignable to type 'number | undefined'. +tests/cases/compiler/intersectionsAndOptionalProperties.ts(20,5): error TS2322: Type 'null' is not assignable to type 'number | undefined'. + + +==== tests/cases/compiler/intersectionsAndOptionalProperties.ts (4 errors) ==== + declare let x: { a?: number, b: string }; + declare let y: { a: null, b: string }; + declare let z: { a: null } & { b: string }; + + x = y; // Error + ~ +!!! error TS2322: Type '{ a: null; b: string; }' is not assignable to type '{ a?: number | undefined; b: string; }'. +!!! error TS2322: Types of property 'a' are incompatible. +!!! error TS2322: Type 'null' is not assignable to type 'number | undefined'. + x = z; // Error + ~ +!!! error TS2322: Type '{ a: null; } & { b: string; }' is not assignable to type '{ a?: number | undefined; b: string; }'. +!!! error TS2322: Types of property 'a' are incompatible. +!!! error TS2322: Type 'null' is not assignable to type 'number | undefined'. + + // Repro from #36604 + + interface To { + field?: number; + anotherField: string; + } + + type From = { field: null } & Omit; + + function foo(v: From) { + let x: To; + x = v; // Error + ~ +!!! error TS2322: Type 'From' is not assignable to type 'To'. +!!! error TS2322: Types of property 'field' are incompatible. +!!! error TS2322: Type 'null' is not assignable to type 'number | undefined'. + x.field = v.field; // Error + ~~~~~~~ +!!! error TS2322: Type 'null' is not assignable to type 'number | undefined'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/intersectionsAndOptionalProperties.js b/tests/baselines/reference/intersectionsAndOptionalProperties.js new file mode 100644 index 0000000000..b2f13a9f67 --- /dev/null +++ b/tests/baselines/reference/intersectionsAndOptionalProperties.js @@ -0,0 +1,33 @@ +//// [intersectionsAndOptionalProperties.ts] +declare let x: { a?: number, b: string }; +declare let y: { a: null, b: string }; +declare let z: { a: null } & { b: string }; + +x = y; // Error +x = z; // Error + +// Repro from #36604 + +interface To { + field?: number; + anotherField: string; +} + +type From = { field: null } & Omit; + +function foo(v: From) { + let x: To; + x = v; // Error + x.field = v.field; // Error +} + + +//// [intersectionsAndOptionalProperties.js] +"use strict"; +x = y; // Error +x = z; // Error +function foo(v) { + var x; + x = v; // Error + x.field = v.field; // Error +} diff --git a/tests/baselines/reference/intersectionsAndOptionalProperties.symbols b/tests/baselines/reference/intersectionsAndOptionalProperties.symbols new file mode 100644 index 0000000000..c5504794e6 --- /dev/null +++ b/tests/baselines/reference/intersectionsAndOptionalProperties.symbols @@ -0,0 +1,64 @@ +=== tests/cases/compiler/intersectionsAndOptionalProperties.ts === +declare let x: { a?: number, b: string }; +>x : Symbol(x, Decl(intersectionsAndOptionalProperties.ts, 0, 11)) +>a : Symbol(a, Decl(intersectionsAndOptionalProperties.ts, 0, 16)) +>b : Symbol(b, Decl(intersectionsAndOptionalProperties.ts, 0, 28)) + +declare let y: { a: null, b: string }; +>y : Symbol(y, Decl(intersectionsAndOptionalProperties.ts, 1, 11)) +>a : Symbol(a, Decl(intersectionsAndOptionalProperties.ts, 1, 16)) +>b : Symbol(b, Decl(intersectionsAndOptionalProperties.ts, 1, 25)) + +declare let z: { a: null } & { b: string }; +>z : Symbol(z, Decl(intersectionsAndOptionalProperties.ts, 2, 11)) +>a : Symbol(a, Decl(intersectionsAndOptionalProperties.ts, 2, 16)) +>b : Symbol(b, Decl(intersectionsAndOptionalProperties.ts, 2, 30)) + +x = y; // Error +>x : Symbol(x, Decl(intersectionsAndOptionalProperties.ts, 0, 11)) +>y : Symbol(y, Decl(intersectionsAndOptionalProperties.ts, 1, 11)) + +x = z; // Error +>x : Symbol(x, Decl(intersectionsAndOptionalProperties.ts, 0, 11)) +>z : Symbol(z, Decl(intersectionsAndOptionalProperties.ts, 2, 11)) + +// Repro from #36604 + +interface To { +>To : Symbol(To, Decl(intersectionsAndOptionalProperties.ts, 5, 6)) + + field?: number; +>field : Symbol(To.field, Decl(intersectionsAndOptionalProperties.ts, 9, 14)) + + anotherField: string; +>anotherField : Symbol(To.anotherField, Decl(intersectionsAndOptionalProperties.ts, 10, 19)) +} + +type From = { field: null } & Omit; +>From : Symbol(From, Decl(intersectionsAndOptionalProperties.ts, 12, 1)) +>field : Symbol(field, Decl(intersectionsAndOptionalProperties.ts, 14, 14)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>To : Symbol(To, Decl(intersectionsAndOptionalProperties.ts, 5, 6)) + +function foo(v: From) { +>foo : Symbol(foo, Decl(intersectionsAndOptionalProperties.ts, 14, 49)) +>v : Symbol(v, Decl(intersectionsAndOptionalProperties.ts, 16, 13)) +>From : Symbol(From, Decl(intersectionsAndOptionalProperties.ts, 12, 1)) + + let x: To; +>x : Symbol(x, Decl(intersectionsAndOptionalProperties.ts, 17, 7)) +>To : Symbol(To, Decl(intersectionsAndOptionalProperties.ts, 5, 6)) + + x = v; // Error +>x : Symbol(x, Decl(intersectionsAndOptionalProperties.ts, 17, 7)) +>v : Symbol(v, Decl(intersectionsAndOptionalProperties.ts, 16, 13)) + + x.field = v.field; // Error +>x.field : Symbol(To.field, Decl(intersectionsAndOptionalProperties.ts, 9, 14)) +>x : Symbol(x, Decl(intersectionsAndOptionalProperties.ts, 17, 7)) +>field : Symbol(To.field, Decl(intersectionsAndOptionalProperties.ts, 9, 14)) +>v.field : Symbol(field, Decl(intersectionsAndOptionalProperties.ts, 14, 14)) +>v : Symbol(v, Decl(intersectionsAndOptionalProperties.ts, 16, 13)) +>field : Symbol(field, Decl(intersectionsAndOptionalProperties.ts, 14, 14)) +} + diff --git a/tests/baselines/reference/intersectionsAndOptionalProperties.types b/tests/baselines/reference/intersectionsAndOptionalProperties.types new file mode 100644 index 0000000000..7f5af60c18 --- /dev/null +++ b/tests/baselines/reference/intersectionsAndOptionalProperties.types @@ -0,0 +1,65 @@ +=== tests/cases/compiler/intersectionsAndOptionalProperties.ts === +declare let x: { a?: number, b: string }; +>x : { a?: number | undefined; b: string; } +>a : number | undefined +>b : string + +declare let y: { a: null, b: string }; +>y : { a: null; b: string; } +>a : null +>null : null +>b : string + +declare let z: { a: null } & { b: string }; +>z : { a: null; } & { b: string; } +>a : null +>null : null +>b : string + +x = y; // Error +>x = y : { a: null; b: string; } +>x : { a?: number | undefined; b: string; } +>y : { a: null; b: string; } + +x = z; // Error +>x = z : { a: null; } & { b: string; } +>x : { a?: number | undefined; b: string; } +>z : { a: null; } & { b: string; } + +// Repro from #36604 + +interface To { + field?: number; +>field : number | undefined + + anotherField: string; +>anotherField : string +} + +type From = { field: null } & Omit; +>From : From +>field : null +>null : null + +function foo(v: From) { +>foo : (v: From) => void +>v : From + + let x: To; +>x : To + + x = v; // Error +>x = v : From +>x : To +>v : From + + x.field = v.field; // Error +>x.field = v.field : null +>x.field : number | undefined +>x : To +>field : number | undefined +>v.field : null +>v : From +>field : null +} + diff --git a/tests/baselines/reference/normalizedIntersectionTooComplex.errors.txt b/tests/baselines/reference/normalizedIntersectionTooComplex.errors.txt index 64e7d7f00c..4e214eff50 100644 --- a/tests/baselines/reference/normalizedIntersectionTooComplex.errors.txt +++ b/tests/baselines/reference/normalizedIntersectionTooComplex.errors.txt @@ -1,5 +1,5 @@ +tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,14): error TS2590: Expression produces a union type that is too complex to represent. tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,40): error TS7006: Parameter 'x' implicitly has an 'any' type. -tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,40): error TS2590: Expression produces a union type that is too complex to represent. ==== tests/cases/compiler/normalizedIntersectionTooComplex.ts (2 errors) ==== @@ -39,8 +39,8 @@ tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,40): error TS2590: E declare var all: keyof Big; const ctor = getCtor(all); const comp = ctor({ common: "ok", ref: x => console.log(x) }); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2590: Expression produces a union type that is too complex to represent. ~ !!! error TS7006: Parameter 'x' implicitly has an 'any' type. - ~~~~~~~~~~~~~~~~~~~ -!!! error TS2590: Expression produces a union type that is too complex to represent. \ No newline at end of file diff --git a/tests/baselines/reference/propTypeValidatorInference.js b/tests/baselines/reference/propTypeValidatorInference.js index 3a6fa04fbe..de1b7e99e1 100644 --- a/tests/baselines/reference/propTypeValidatorInference.js +++ b/tests/baselines/reference/propTypeValidatorInference.js @@ -14,7 +14,7 @@ export interface Validator { [nominalTypeHack]?: T; } -export interface Requireable extends Validator { +export interface Requireable extends Validator { isRequired: Validator>; } diff --git a/tests/baselines/reference/propTypeValidatorInference.symbols b/tests/baselines/reference/propTypeValidatorInference.symbols index 32a4a3c1ab..320c2c46bc 100644 --- a/tests/baselines/reference/propTypeValidatorInference.symbols +++ b/tests/baselines/reference/propTypeValidatorInference.symbols @@ -59,14 +59,14 @@ export interface Validator { >T : Symbol(T, Decl(index.d.ts, 8, 27)) } -export interface Requireable extends Validator { +export interface Requireable extends Validator { >Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1)) >T : Symbol(T, Decl(index.d.ts, 13, 29)) >Validator : Symbol(Validator, Decl(index.d.ts, 6, 72)) >T : Symbol(T, Decl(index.d.ts, 13, 29)) isRequired: Validator>; ->isRequired : Symbol(Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(Requireable.isRequired, Decl(index.d.ts, 13, 54)) >Validator : Symbol(Validator, Decl(index.d.ts, 6, 72)) >NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) >T : Symbol(T, Decl(index.d.ts, 13, 29)) @@ -202,11 +202,11 @@ const innerProps = { foo: PropTypes.string.isRequired, >foo : Symbol(foo, Decl(file.ts, 18, 20)) ->PropTypes.string.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.string.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.string : Symbol(PropTypes.string, Decl(index.d.ts, 27, 12)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >string : Symbol(PropTypes.string, Decl(index.d.ts, 27, 12)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) bar: PropTypes.bool, >bar : Symbol(bar, Decl(file.ts, 19, 37)) @@ -242,11 +242,11 @@ const arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({ bar: PropTypes.number.isRequired >bar : Symbol(bar, Decl(file.ts, 25, 26)) ->PropTypes.number.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.number.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.number : Symbol(PropTypes.number, Decl(index.d.ts, 28, 12)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >number : Symbol(PropTypes.number, Decl(index.d.ts, 28, 12)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) })]; @@ -263,37 +263,37 @@ const propTypes: PropTypesMap = { array: PropTypes.array.isRequired, >array : Symbol(array, Decl(file.ts, 31, 23)) ->PropTypes.array.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.array.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.array : Symbol(PropTypes.array, Decl(index.d.ts, 25, 12)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >array : Symbol(PropTypes.array, Decl(index.d.ts, 25, 12)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) bool: PropTypes.bool.isRequired, >bool : Symbol(bool, Decl(file.ts, 32, 38)) ->PropTypes.bool.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.bool.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) shape: PropTypes.shape(innerProps).isRequired, >shape : Symbol(shape, Decl(file.ts, 33, 36)) ->PropTypes.shape(innerProps).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.shape(innerProps).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) >innerProps : Symbol(innerProps, Decl(file.ts, 18, 5)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, >oneOfType : Symbol(oneOfType, Decl(file.ts, 34, 50)) ->PropTypes.oneOfType(arrayOfTypes).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.oneOfType(arrayOfTypes).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.oneOfType : Symbol(PropTypes.oneOfType, Decl(index.d.ts, 29, 89)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >oneOfType : Symbol(PropTypes.oneOfType, Decl(index.d.ts, 29, 89)) >arrayOfTypes : Symbol(arrayOfTypes, Decl(file.ts, 24, 5)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) }; @@ -309,37 +309,37 @@ const propTypesWithoutAnnotation = { array: PropTypes.array.isRequired, >array : Symbol(array, Decl(file.ts, 40, 23)) ->PropTypes.array.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.array.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.array : Symbol(PropTypes.array, Decl(index.d.ts, 25, 12)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >array : Symbol(PropTypes.array, Decl(index.d.ts, 25, 12)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) bool: PropTypes.bool.isRequired, >bool : Symbol(bool, Decl(file.ts, 41, 38)) ->PropTypes.bool.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.bool.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) shape: PropTypes.shape(innerProps).isRequired, >shape : Symbol(shape, Decl(file.ts, 42, 36)) ->PropTypes.shape(innerProps).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.shape(innerProps).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) >innerProps : Symbol(innerProps, Decl(file.ts, 18, 5)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, >oneOfType : Symbol(oneOfType, Decl(file.ts, 43, 50)) ->PropTypes.oneOfType(arrayOfTypes).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.oneOfType(arrayOfTypes).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.oneOfType : Symbol(PropTypes.oneOfType, Decl(index.d.ts, 29, 89)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >oneOfType : Symbol(PropTypes.oneOfType, Decl(index.d.ts, 29, 89)) >arrayOfTypes : Symbol(arrayOfTypes, Decl(file.ts, 24, 5)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) }; diff --git a/tests/baselines/reference/propTypeValidatorInference.types b/tests/baselines/reference/propTypeValidatorInference.types index eb292dac5c..5276e7837f 100644 --- a/tests/baselines/reference/propTypeValidatorInference.types +++ b/tests/baselines/reference/propTypeValidatorInference.types @@ -35,9 +35,7 @@ export interface Validator { >nominalTypeHack : unique symbol } -export interface Requireable extends Validator { ->null : null - +export interface Requireable extends Validator { isRequired: Validator>; >isRequired : Validator> } diff --git a/tests/cases/compiler/intersectionsAndOptionalProperties.ts b/tests/cases/compiler/intersectionsAndOptionalProperties.ts new file mode 100644 index 0000000000..a5bc4a1580 --- /dev/null +++ b/tests/cases/compiler/intersectionsAndOptionalProperties.ts @@ -0,0 +1,23 @@ +// @strict: true + +declare let x: { a?: number, b: string }; +declare let y: { a: null, b: string }; +declare let z: { a: null } & { b: string }; + +x = y; // Error +x = z; // Error + +// Repro from #36604 + +interface To { + field?: number; + anotherField: string; +} + +type From = { field: null } & Omit; + +function foo(v: From) { + let x: To; + x = v; // Error + x.field = v.field; // Error +} diff --git a/tests/cases/compiler/propTypeValidatorInference.ts b/tests/cases/compiler/propTypeValidatorInference.ts index 54030ab91a..9f6120a5d6 100644 --- a/tests/cases/compiler/propTypeValidatorInference.ts +++ b/tests/cases/compiler/propTypeValidatorInference.ts @@ -13,7 +13,7 @@ export interface Validator { [nominalTypeHack]?: T; } -export interface Requireable extends Validator { +export interface Requireable extends Validator { isRequired: Validator>; }