Skip to content

Commit

Permalink
Improve excess property checking for intersections (#32582)
Browse files Browse the repository at this point in the history
* 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 b8dccff.
  • Loading branch information
sandersn committed Aug 6, 2019
1 parent d00056f commit 480b739
Show file tree
Hide file tree
Showing 16 changed files with 220 additions and 58 deletions.
54 changes: 27 additions & 27 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

@@ -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

}],
}
}

Expand Up @@ -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'.
Expand Down
Expand Up @@ -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

Expand Down Expand Up @@ -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: '',
Expand Down
Expand Up @@ -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))
Expand Down
Expand Up @@ -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; }
Expand Down
16 changes: 6 additions & 10 deletions tests/baselines/reference/weakType.errors.txt
Expand Up @@ -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) ====
Expand Down Expand Up @@ -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; }'.


6 changes: 3 additions & 3 deletions tests/baselines/reference/weakType.js
Expand Up @@ -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



Expand Down Expand Up @@ -89,4 +89,4 @@ var K = /** @class */ (function () {
return K;
}());
var ctor = K;
var weak = unknown;
var weak = propertiesWrong;
10 changes: 5 additions & 5 deletions tests/baselines/reference/weakType.symbols
Expand Up @@ -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))


8 changes: 4 additions & 4 deletions tests/baselines/reference/weakType.types
Expand Up @@ -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; }
Expand All @@ -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,
}],
}
}
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions tests/cases/compiler/weakType.ts
Expand Up @@ -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

2 changes: 1 addition & 1 deletion tests/cases/user/prettier/prettier
Submodule prettier updated 198 files

0 comments on commit 480b739

Please sign in to comment.