From c95d6f799dd711852e4cff7fb49f7a5a4386e705 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 30 Mar 2022 23:06:48 +0000 Subject: [PATCH 1/6] Added test case. --- ...contextualNarrowingFromUnknownToObjects.ts | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts diff --git a/tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts b/tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts new file mode 100644 index 0000000000000..c5488d3ee772f --- /dev/null +++ b/tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts @@ -0,0 +1,63 @@ + +// @strictNullChecks: true, false +// @target: esnext + +declare function keysOfEmptyObject(o: {}): string[]; +declare function keysOfNonPrimitive(o: object): string[]; + +namespace implicitConstraints { + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + return [a, b]; + } + return undefined; + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + return [a, b]; + } + return undefined; + } +} + +// Explicit Constraints of 'unknown' +namespace explicitConstraintsOfUnknown { + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + return [a, b]; + } + return undefined; + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + return [a, b]; + } + return undefined; + } +} From d4e363a5b5504b8333e76f77adf6a983274bcc46 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 30 Mar 2022 23:06:58 +0000 Subject: [PATCH 2/6] Accepted baselines. --- ...Objects(strictnullchecks=false).errors.txt | 77 +++++ ...nknownToObjects(strictnullchecks=false).js | 122 ++++++++ ...nToObjects(strictnullchecks=false).symbols | 218 ++++++++++++++ ...ownToObjects(strictnullchecks=false).types | 270 ++++++++++++++++++ ...oObjects(strictnullchecks=true).errors.txt | 93 ++++++ ...UnknownToObjects(strictnullchecks=true).js | 122 ++++++++ ...wnToObjects(strictnullchecks=true).symbols | 218 ++++++++++++++ ...nownToObjects(strictnullchecks=true).types | 270 ++++++++++++++++++ 8 files changed, 1390 insertions(+) create mode 100644 tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).errors.txt create mode 100644 tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).js create mode 100644 tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).symbols create mode 100644 tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).types create mode 100644 tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).errors.txt create mode 100644 tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).js create mode 100644 tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).symbols create mode 100644 tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).types diff --git a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).errors.txt b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).errors.txt new file mode 100644 index 0000000000000..47a6bdefc27c4 --- /dev/null +++ b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).errors.txt @@ -0,0 +1,77 @@ +tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(25,32): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. +tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(25,65): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. +tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(54,32): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. + Type 'unknown' is not assignable to type 'object'. +tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(54,65): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. + + +==== tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts (4 errors) ==== + declare function keysOfEmptyObject(o: {}): string[]; + declare function keysOfNonPrimitive(o: object): string[]; + + namespace implicitConstraints { + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + return [a, b]; + } + return undefined; + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. + return [a, b]; + } + return undefined; + } + } + + // Explicit Constraints of 'unknown' + namespace explicitConstraintsOfUnknown { + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + return [a, b]; + } + return undefined; + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. +!!! error TS2345: Type 'unknown' is not assignable to type 'object'. + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. + return [a, b]; + } + return undefined; + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).js b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).js new file mode 100644 index 0000000000000..15db68e11de77 --- /dev/null +++ b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).js @@ -0,0 +1,122 @@ +//// [contextualNarrowingFromUnknownToObjects.ts] +declare function keysOfEmptyObject(o: {}): string[]; +declare function keysOfNonPrimitive(o: object): string[]; + +namespace implicitConstraints { + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + return [a, b]; + } + return undefined; + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + return [a, b]; + } + return undefined; + } +} + +// Explicit Constraints of 'unknown' +namespace explicitConstraintsOfUnknown { + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + return [a, b]; + } + return undefined; + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + return [a, b]; + } + return undefined; + } +} + + +//// [contextualNarrowingFromUnknownToObjects.js] +var implicitConstraints; +(function (implicitConstraints) { + function keyLengthsEqualUsingEmptyObjectFn(a, b) { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + return [a, b]; + } + return undefined; + } + implicitConstraints.keyLengthsEqualUsingEmptyObjectFn = keyLengthsEqualUsingEmptyObjectFn; + function keyLengthsEqualUsingNonPrimitiveFn(a, b) { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + return [a, b]; + } + return undefined; + } + implicitConstraints.keyLengthsEqualUsingNonPrimitiveFn = keyLengthsEqualUsingNonPrimitiveFn; +})(implicitConstraints || (implicitConstraints = {})); +// Explicit Constraints of 'unknown' +var explicitConstraintsOfUnknown; +(function (explicitConstraintsOfUnknown) { + function keyLengthsEqualUsingEmptyObjectFn(a, b) { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + return [a, b]; + } + return undefined; + } + explicitConstraintsOfUnknown.keyLengthsEqualUsingEmptyObjectFn = keyLengthsEqualUsingEmptyObjectFn; + function keyLengthsEqualUsingNonPrimitiveFn(a, b) { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + return [a, b]; + } + return undefined; + } + explicitConstraintsOfUnknown.keyLengthsEqualUsingNonPrimitiveFn = keyLengthsEqualUsingNonPrimitiveFn; +})(explicitConstraintsOfUnknown || (explicitConstraintsOfUnknown = {})); diff --git a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).symbols b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).symbols new file mode 100644 index 0000000000000..ea7e8c92d0ebb --- /dev/null +++ b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).symbols @@ -0,0 +1,218 @@ +=== tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts === +declare function keysOfEmptyObject(o: {}): string[]; +>keysOfEmptyObject : Symbol(keysOfEmptyObject, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 0)) +>o : Symbol(o, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 35)) + +declare function keysOfNonPrimitive(o: object): string[]; +>keysOfNonPrimitive : Symbol(keysOfNonPrimitive, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 52)) +>o : Symbol(o, Decl(contextualNarrowingFromUnknownToObjects.ts, 1, 36)) + +namespace implicitConstraints { +>implicitConstraints : Symbol(implicitConstraints, Decl(contextualNarrowingFromUnknownToObjects.ts, 1, 57)) + + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingEmptyObjectFn : Symbol(keyLengthsEqualUsingEmptyObjectFn, Decl(contextualNarrowingFromUnknownToObjects.ts, 3, 31)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 54)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 57)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 54)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 62)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 54)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 54)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 54)) + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 57)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 62)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 57)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 62)) + + return undefined; +>undefined : Symbol(undefined) + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 57)) +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 62)) + + return undefined; +>undefined : Symbol(undefined) + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { +>keysOfEmptyObject(a).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfEmptyObject : Symbol(keysOfEmptyObject, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 0)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 57)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfEmptyObject(b).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfEmptyObject : Symbol(keysOfEmptyObject, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 0)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 62)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + return [a, b]; +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 57)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 62)) + } + return undefined; +>undefined : Symbol(undefined) + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingNonPrimitiveFn : Symbol(keyLengthsEqualUsingNonPrimitiveFn, Decl(contextualNarrowingFromUnknownToObjects.ts, 15, 5)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 55)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 58)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 55)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 63)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 55)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 55)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 55)) + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 58)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 63)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 58)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 63)) + + return undefined; +>undefined : Symbol(undefined) + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 58)) +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 63)) + + return undefined; +>undefined : Symbol(undefined) + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { +>keysOfNonPrimitive(a).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfNonPrimitive : Symbol(keysOfNonPrimitive, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 52)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 58)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfNonPrimitive(b).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfNonPrimitive : Symbol(keysOfNonPrimitive, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 52)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 63)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + return [a, b]; +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 58)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 63)) + } + return undefined; +>undefined : Symbol(undefined) + } +} + +// Explicit Constraints of 'unknown' +namespace explicitConstraintsOfUnknown { +>explicitConstraintsOfUnknown : Symbol(explicitConstraintsOfUnknown, Decl(contextualNarrowingFromUnknownToObjects.ts, 29, 1)) + + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingEmptyObjectFn : Symbol(keyLengthsEqualUsingEmptyObjectFn, Decl(contextualNarrowingFromUnknownToObjects.ts, 32, 40)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 54)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 73)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 54)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 78)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 54)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 54)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 54)) + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 73)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 78)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 73)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 78)) + + return undefined; +>undefined : Symbol(undefined) + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 73)) +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 78)) + + return undefined; +>undefined : Symbol(undefined) + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { +>keysOfEmptyObject(a).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfEmptyObject : Symbol(keysOfEmptyObject, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 0)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 73)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfEmptyObject(b).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfEmptyObject : Symbol(keysOfEmptyObject, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 0)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 78)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + return [a, b]; +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 73)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 78)) + } + return undefined; +>undefined : Symbol(undefined) + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingNonPrimitiveFn : Symbol(keyLengthsEqualUsingNonPrimitiveFn, Decl(contextualNarrowingFromUnknownToObjects.ts, 44, 5)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 55)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 74)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 55)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 79)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 55)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 55)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 55)) + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 74)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 79)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 74)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 79)) + + return undefined; +>undefined : Symbol(undefined) + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 74)) +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 79)) + + return undefined; +>undefined : Symbol(undefined) + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { +>keysOfNonPrimitive(a).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfNonPrimitive : Symbol(keysOfNonPrimitive, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 52)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 74)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfNonPrimitive(b).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfNonPrimitive : Symbol(keysOfNonPrimitive, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 52)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 79)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + return [a, b]; +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 74)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 79)) + } + return undefined; +>undefined : Symbol(undefined) + } +} + diff --git a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).types b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).types new file mode 100644 index 0000000000000..b5800e2bb7d19 --- /dev/null +++ b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).types @@ -0,0 +1,270 @@ +=== tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts === +declare function keysOfEmptyObject(o: {}): string[]; +>keysOfEmptyObject : (o: {}) => string[] +>o : {} + +declare function keysOfNonPrimitive(o: object): string[]; +>keysOfNonPrimitive : (o: object) => string[] +>o : object + +namespace implicitConstraints { +>implicitConstraints : typeof implicitConstraints + + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingEmptyObjectFn : (a: T, b: T) => [T, T] | undefined +>a : T +>b : T + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>typeof a !== "object" || typeof b !== "object" || !a || !b : boolean +>typeof a !== "object" || typeof b !== "object" || !a : boolean +>typeof a !== "object" || typeof b !== "object" : boolean +>typeof a !== "object" : boolean +>typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>a : T +>"object" : "object" +>typeof b !== "object" : boolean +>typeof b : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>b : T +>"object" : "object" +>!a : boolean +>a : T +>!b : boolean +>b : T + + return undefined; +>undefined : undefined + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray(a) || Array.isArray(b) : boolean +>Array.isArray(a) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>a : T +>Array.isArray(b) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>b : T + + return undefined; +>undefined : undefined + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { +>keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length : boolean +>keysOfEmptyObject(a).length : number +>keysOfEmptyObject(a) : string[] +>keysOfEmptyObject : (o: {}) => string[] +>a : T +>length : number +>keysOfEmptyObject(b).length : number +>keysOfEmptyObject(b) : string[] +>keysOfEmptyObject : (o: {}) => string[] +>b : T +>length : number + + return [a, b]; +>[a, b] : [T, T] +>a : T +>b : T + } + return undefined; +>undefined : undefined + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingNonPrimitiveFn : (a: T, b: T) => [T, T] | undefined +>a : T +>b : T + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>typeof a !== "object" || typeof b !== "object" || !a || !b : boolean +>typeof a !== "object" || typeof b !== "object" || !a : boolean +>typeof a !== "object" || typeof b !== "object" : boolean +>typeof a !== "object" : boolean +>typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>a : T +>"object" : "object" +>typeof b !== "object" : boolean +>typeof b : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>b : T +>"object" : "object" +>!a : boolean +>a : T +>!b : boolean +>b : T + + return undefined; +>undefined : undefined + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray(a) || Array.isArray(b) : boolean +>Array.isArray(a) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>a : T +>Array.isArray(b) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>b : T + + return undefined; +>undefined : undefined + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { +>keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length : boolean +>keysOfNonPrimitive(a).length : number +>keysOfNonPrimitive(a) : string[] +>keysOfNonPrimitive : (o: object) => string[] +>a : T +>length : number +>keysOfNonPrimitive(b).length : number +>keysOfNonPrimitive(b) : string[] +>keysOfNonPrimitive : (o: object) => string[] +>b : T +>length : number + + return [a, b]; +>[a, b] : [T, T] +>a : T +>b : T + } + return undefined; +>undefined : undefined + } +} + +// Explicit Constraints of 'unknown' +namespace explicitConstraintsOfUnknown { +>explicitConstraintsOfUnknown : typeof explicitConstraintsOfUnknown + + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingEmptyObjectFn : (a: T, b: T) => [T, T] | undefined +>a : T +>b : T + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>typeof a !== "object" || typeof b !== "object" || !a || !b : boolean +>typeof a !== "object" || typeof b !== "object" || !a : boolean +>typeof a !== "object" || typeof b !== "object" : boolean +>typeof a !== "object" : boolean +>typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>a : T +>"object" : "object" +>typeof b !== "object" : boolean +>typeof b : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>b : T +>"object" : "object" +>!a : boolean +>a : T +>!b : boolean +>b : T + + return undefined; +>undefined : undefined + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray(a) || Array.isArray(b) : boolean +>Array.isArray(a) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>a : T +>Array.isArray(b) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>b : T + + return undefined; +>undefined : undefined + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { +>keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length : boolean +>keysOfEmptyObject(a).length : number +>keysOfEmptyObject(a) : string[] +>keysOfEmptyObject : (o: {}) => string[] +>a : T +>length : number +>keysOfEmptyObject(b).length : number +>keysOfEmptyObject(b) : string[] +>keysOfEmptyObject : (o: {}) => string[] +>b : T +>length : number + + return [a, b]; +>[a, b] : [T, T] +>a : T +>b : T + } + return undefined; +>undefined : undefined + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingNonPrimitiveFn : (a: T, b: T) => [T, T] | undefined +>a : T +>b : T + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>typeof a !== "object" || typeof b !== "object" || !a || !b : boolean +>typeof a !== "object" || typeof b !== "object" || !a : boolean +>typeof a !== "object" || typeof b !== "object" : boolean +>typeof a !== "object" : boolean +>typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>a : T +>"object" : "object" +>typeof b !== "object" : boolean +>typeof b : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>b : T +>"object" : "object" +>!a : boolean +>a : T +>!b : boolean +>b : T + + return undefined; +>undefined : undefined + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray(a) || Array.isArray(b) : boolean +>Array.isArray(a) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>a : T +>Array.isArray(b) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>b : T + + return undefined; +>undefined : undefined + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { +>keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length : boolean +>keysOfNonPrimitive(a).length : number +>keysOfNonPrimitive(a) : string[] +>keysOfNonPrimitive : (o: object) => string[] +>a : T +>length : number +>keysOfNonPrimitive(b).length : number +>keysOfNonPrimitive(b) : string[] +>keysOfNonPrimitive : (o: object) => string[] +>b : T +>length : number + + return [a, b]; +>[a, b] : [T, T] +>a : T +>b : T + } + return undefined; +>undefined : undefined + } +} + diff --git a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).errors.txt b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).errors.txt new file mode 100644 index 0000000000000..a9aaada48f448 --- /dev/null +++ b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).errors.txt @@ -0,0 +1,93 @@ +tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(12,31): error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. +tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(12,63): error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. +tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(25,32): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. +tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(25,65): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. +tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(41,31): error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. + Type 'unknown' is not assignable to type '{}'. +tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(41,63): error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. +tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(54,32): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. + Type 'unknown' is not assignable to type 'object'. +tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(54,65): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. + + +==== tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts (8 errors) ==== + declare function keysOfEmptyObject(o: {}): string[]; + declare function keysOfNonPrimitive(o: object): string[]; + + namespace implicitConstraints { + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. +!!! related TS2208 tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts:5:55: This type parameter probably needs an `extends object` constraint. + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. +!!! related TS2208 tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts:5:55: This type parameter probably needs an `extends object` constraint. + return [a, b]; + } + return undefined; + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. + return [a, b]; + } + return undefined; + } + } + + // Explicit Constraints of 'unknown' + namespace explicitConstraintsOfUnknown { + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. +!!! error TS2345: Type 'unknown' is not assignable to type '{}'. + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. + return [a, b]; + } + return undefined; + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. +!!! error TS2345: Type 'unknown' is not assignable to type 'object'. + ~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. + return [a, b]; + } + return undefined; + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).js b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).js new file mode 100644 index 0000000000000..15db68e11de77 --- /dev/null +++ b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).js @@ -0,0 +1,122 @@ +//// [contextualNarrowingFromUnknownToObjects.ts] +declare function keysOfEmptyObject(o: {}): string[]; +declare function keysOfNonPrimitive(o: object): string[]; + +namespace implicitConstraints { + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + return [a, b]; + } + return undefined; + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + return [a, b]; + } + return undefined; + } +} + +// Explicit Constraints of 'unknown' +namespace explicitConstraintsOfUnknown { + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + return [a, b]; + } + return undefined; + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + return [a, b]; + } + return undefined; + } +} + + +//// [contextualNarrowingFromUnknownToObjects.js] +var implicitConstraints; +(function (implicitConstraints) { + function keyLengthsEqualUsingEmptyObjectFn(a, b) { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + return [a, b]; + } + return undefined; + } + implicitConstraints.keyLengthsEqualUsingEmptyObjectFn = keyLengthsEqualUsingEmptyObjectFn; + function keyLengthsEqualUsingNonPrimitiveFn(a, b) { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + return [a, b]; + } + return undefined; + } + implicitConstraints.keyLengthsEqualUsingNonPrimitiveFn = keyLengthsEqualUsingNonPrimitiveFn; +})(implicitConstraints || (implicitConstraints = {})); +// Explicit Constraints of 'unknown' +var explicitConstraintsOfUnknown; +(function (explicitConstraintsOfUnknown) { + function keyLengthsEqualUsingEmptyObjectFn(a, b) { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { + return [a, b]; + } + return undefined; + } + explicitConstraintsOfUnknown.keyLengthsEqualUsingEmptyObjectFn = keyLengthsEqualUsingEmptyObjectFn; + function keyLengthsEqualUsingNonPrimitiveFn(a, b) { + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { + return undefined; + } + if (Array.isArray(a) || Array.isArray(b)) { + return undefined; + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { + return [a, b]; + } + return undefined; + } + explicitConstraintsOfUnknown.keyLengthsEqualUsingNonPrimitiveFn = keyLengthsEqualUsingNonPrimitiveFn; +})(explicitConstraintsOfUnknown || (explicitConstraintsOfUnknown = {})); diff --git a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).symbols b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).symbols new file mode 100644 index 0000000000000..ea7e8c92d0ebb --- /dev/null +++ b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).symbols @@ -0,0 +1,218 @@ +=== tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts === +declare function keysOfEmptyObject(o: {}): string[]; +>keysOfEmptyObject : Symbol(keysOfEmptyObject, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 0)) +>o : Symbol(o, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 35)) + +declare function keysOfNonPrimitive(o: object): string[]; +>keysOfNonPrimitive : Symbol(keysOfNonPrimitive, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 52)) +>o : Symbol(o, Decl(contextualNarrowingFromUnknownToObjects.ts, 1, 36)) + +namespace implicitConstraints { +>implicitConstraints : Symbol(implicitConstraints, Decl(contextualNarrowingFromUnknownToObjects.ts, 1, 57)) + + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingEmptyObjectFn : Symbol(keyLengthsEqualUsingEmptyObjectFn, Decl(contextualNarrowingFromUnknownToObjects.ts, 3, 31)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 54)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 57)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 54)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 62)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 54)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 54)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 54)) + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 57)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 62)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 57)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 62)) + + return undefined; +>undefined : Symbol(undefined) + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 57)) +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 62)) + + return undefined; +>undefined : Symbol(undefined) + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { +>keysOfEmptyObject(a).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfEmptyObject : Symbol(keysOfEmptyObject, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 0)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 57)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfEmptyObject(b).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfEmptyObject : Symbol(keysOfEmptyObject, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 0)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 62)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + return [a, b]; +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 57)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 4, 62)) + } + return undefined; +>undefined : Symbol(undefined) + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingNonPrimitiveFn : Symbol(keyLengthsEqualUsingNonPrimitiveFn, Decl(contextualNarrowingFromUnknownToObjects.ts, 15, 5)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 55)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 58)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 55)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 63)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 55)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 55)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 55)) + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 58)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 63)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 58)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 63)) + + return undefined; +>undefined : Symbol(undefined) + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 58)) +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 63)) + + return undefined; +>undefined : Symbol(undefined) + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { +>keysOfNonPrimitive(a).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfNonPrimitive : Symbol(keysOfNonPrimitive, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 52)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 58)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfNonPrimitive(b).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfNonPrimitive : Symbol(keysOfNonPrimitive, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 52)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 63)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + return [a, b]; +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 58)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 17, 63)) + } + return undefined; +>undefined : Symbol(undefined) + } +} + +// Explicit Constraints of 'unknown' +namespace explicitConstraintsOfUnknown { +>explicitConstraintsOfUnknown : Symbol(explicitConstraintsOfUnknown, Decl(contextualNarrowingFromUnknownToObjects.ts, 29, 1)) + + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingEmptyObjectFn : Symbol(keyLengthsEqualUsingEmptyObjectFn, Decl(contextualNarrowingFromUnknownToObjects.ts, 32, 40)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 54)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 73)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 54)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 78)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 54)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 54)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 54)) + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 73)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 78)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 73)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 78)) + + return undefined; +>undefined : Symbol(undefined) + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 73)) +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 78)) + + return undefined; +>undefined : Symbol(undefined) + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { +>keysOfEmptyObject(a).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfEmptyObject : Symbol(keysOfEmptyObject, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 0)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 73)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfEmptyObject(b).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfEmptyObject : Symbol(keysOfEmptyObject, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 0)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 78)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + return [a, b]; +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 73)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 33, 78)) + } + return undefined; +>undefined : Symbol(undefined) + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingNonPrimitiveFn : Symbol(keyLengthsEqualUsingNonPrimitiveFn, Decl(contextualNarrowingFromUnknownToObjects.ts, 44, 5)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 55)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 74)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 55)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 79)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 55)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 55)) +>T : Symbol(T, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 55)) + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 74)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 79)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 74)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 79)) + + return undefined; +>undefined : Symbol(undefined) + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 74)) +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 3 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 79)) + + return undefined; +>undefined : Symbol(undefined) + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { +>keysOfNonPrimitive(a).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfNonPrimitive : Symbol(keysOfNonPrimitive, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 52)) +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 74)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfNonPrimitive(b).length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>keysOfNonPrimitive : Symbol(keysOfNonPrimitive, Decl(contextualNarrowingFromUnknownToObjects.ts, 0, 52)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 79)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + + return [a, b]; +>a : Symbol(a, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 74)) +>b : Symbol(b, Decl(contextualNarrowingFromUnknownToObjects.ts, 46, 79)) + } + return undefined; +>undefined : Symbol(undefined) + } +} + diff --git a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).types b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).types new file mode 100644 index 0000000000000..b5800e2bb7d19 --- /dev/null +++ b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).types @@ -0,0 +1,270 @@ +=== tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts === +declare function keysOfEmptyObject(o: {}): string[]; +>keysOfEmptyObject : (o: {}) => string[] +>o : {} + +declare function keysOfNonPrimitive(o: object): string[]; +>keysOfNonPrimitive : (o: object) => string[] +>o : object + +namespace implicitConstraints { +>implicitConstraints : typeof implicitConstraints + + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingEmptyObjectFn : (a: T, b: T) => [T, T] | undefined +>a : T +>b : T + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>typeof a !== "object" || typeof b !== "object" || !a || !b : boolean +>typeof a !== "object" || typeof b !== "object" || !a : boolean +>typeof a !== "object" || typeof b !== "object" : boolean +>typeof a !== "object" : boolean +>typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>a : T +>"object" : "object" +>typeof b !== "object" : boolean +>typeof b : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>b : T +>"object" : "object" +>!a : boolean +>a : T +>!b : boolean +>b : T + + return undefined; +>undefined : undefined + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray(a) || Array.isArray(b) : boolean +>Array.isArray(a) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>a : T +>Array.isArray(b) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>b : T + + return undefined; +>undefined : undefined + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { +>keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length : boolean +>keysOfEmptyObject(a).length : number +>keysOfEmptyObject(a) : string[] +>keysOfEmptyObject : (o: {}) => string[] +>a : T +>length : number +>keysOfEmptyObject(b).length : number +>keysOfEmptyObject(b) : string[] +>keysOfEmptyObject : (o: {}) => string[] +>b : T +>length : number + + return [a, b]; +>[a, b] : [T, T] +>a : T +>b : T + } + return undefined; +>undefined : undefined + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingNonPrimitiveFn : (a: T, b: T) => [T, T] | undefined +>a : T +>b : T + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>typeof a !== "object" || typeof b !== "object" || !a || !b : boolean +>typeof a !== "object" || typeof b !== "object" || !a : boolean +>typeof a !== "object" || typeof b !== "object" : boolean +>typeof a !== "object" : boolean +>typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>a : T +>"object" : "object" +>typeof b !== "object" : boolean +>typeof b : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>b : T +>"object" : "object" +>!a : boolean +>a : T +>!b : boolean +>b : T + + return undefined; +>undefined : undefined + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray(a) || Array.isArray(b) : boolean +>Array.isArray(a) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>a : T +>Array.isArray(b) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>b : T + + return undefined; +>undefined : undefined + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { +>keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length : boolean +>keysOfNonPrimitive(a).length : number +>keysOfNonPrimitive(a) : string[] +>keysOfNonPrimitive : (o: object) => string[] +>a : T +>length : number +>keysOfNonPrimitive(b).length : number +>keysOfNonPrimitive(b) : string[] +>keysOfNonPrimitive : (o: object) => string[] +>b : T +>length : number + + return [a, b]; +>[a, b] : [T, T] +>a : T +>b : T + } + return undefined; +>undefined : undefined + } +} + +// Explicit Constraints of 'unknown' +namespace explicitConstraintsOfUnknown { +>explicitConstraintsOfUnknown : typeof explicitConstraintsOfUnknown + + export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingEmptyObjectFn : (a: T, b: T) => [T, T] | undefined +>a : T +>b : T + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>typeof a !== "object" || typeof b !== "object" || !a || !b : boolean +>typeof a !== "object" || typeof b !== "object" || !a : boolean +>typeof a !== "object" || typeof b !== "object" : boolean +>typeof a !== "object" : boolean +>typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>a : T +>"object" : "object" +>typeof b !== "object" : boolean +>typeof b : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>b : T +>"object" : "object" +>!a : boolean +>a : T +>!b : boolean +>b : T + + return undefined; +>undefined : undefined + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray(a) || Array.isArray(b) : boolean +>Array.isArray(a) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>a : T +>Array.isArray(b) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>b : T + + return undefined; +>undefined : undefined + } + if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { +>keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length : boolean +>keysOfEmptyObject(a).length : number +>keysOfEmptyObject(a) : string[] +>keysOfEmptyObject : (o: {}) => string[] +>a : T +>length : number +>keysOfEmptyObject(b).length : number +>keysOfEmptyObject(b) : string[] +>keysOfEmptyObject : (o: {}) => string[] +>b : T +>length : number + + return [a, b]; +>[a, b] : [T, T] +>a : T +>b : T + } + return undefined; +>undefined : undefined + } + + export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { +>keyLengthsEqualUsingNonPrimitiveFn : (a: T, b: T) => [T, T] | undefined +>a : T +>b : T + + if (typeof a !== "object" || typeof b !== "object" || !a || !b) { +>typeof a !== "object" || typeof b !== "object" || !a || !b : boolean +>typeof a !== "object" || typeof b !== "object" || !a : boolean +>typeof a !== "object" || typeof b !== "object" : boolean +>typeof a !== "object" : boolean +>typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>a : T +>"object" : "object" +>typeof b !== "object" : boolean +>typeof b : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>b : T +>"object" : "object" +>!a : boolean +>a : T +>!b : boolean +>b : T + + return undefined; +>undefined : undefined + } + if (Array.isArray(a) || Array.isArray(b)) { +>Array.isArray(a) || Array.isArray(b) : boolean +>Array.isArray(a) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>a : T +>Array.isArray(b) : boolean +>Array.isArray : (arg: any) => arg is any[] +>Array : ArrayConstructor +>isArray : (arg: any) => arg is any[] +>b : T + + return undefined; +>undefined : undefined + } + if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { +>keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length : boolean +>keysOfNonPrimitive(a).length : number +>keysOfNonPrimitive(a) : string[] +>keysOfNonPrimitive : (o: object) => string[] +>a : T +>length : number +>keysOfNonPrimitive(b).length : number +>keysOfNonPrimitive(b) : string[] +>keysOfNonPrimitive : (o: object) => string[] +>b : T +>length : number + + return [a, b]; +>[a, b] : [T, T] +>a : T +>b : T + } + return undefined; +>undefined : undefined + } +} + From 21fde45c6f202de3471e2d54c2260f5a8975cd20 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 4 Apr 2022 22:02:05 +0000 Subject: [PATCH 3/6] Try to change some logic for contextual narrowing for any instantiable type to empty objects. --- src/compiler/checker.ts | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1506c4809ef33..ec7e398f1000d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25439,7 +25439,7 @@ namespace ts { return !!(type.flags & TypeFlags.Instantiable && !maybeTypeOfKind(getBaseConstraintOrType(type), TypeFlags.Nullable)); } - function hasContextualTypeWithNoGenericTypes(node: Node, checkMode: CheckMode | undefined) { + function tryGetContextualTypeWithNoGenericTypes(node: Node, checkMode: CheckMode | undefined) { // Computing the contextual type for a child of a JSX element involves resolving the type of the // element's tag name, so we exclude that here to avoid circularities. // If check mode has `CheckMode.RestBindingElement`, we skip binding pattern contextual types, @@ -25449,7 +25449,7 @@ namespace ts { (checkMode && checkMode & CheckMode.RestBindingElement ? getContextualType(node, ContextFlags.SkipBindingPatterns) : getContextualType(node)); - return contextualType && !isGenericType(contextualType); + return contextualType && !isGenericType(contextualType) ? contextualType : undefined; } function getNarrowableTypeForReference(type: Type, reference: Node, checkMode?: CheckMode) { @@ -25460,10 +25460,25 @@ namespace ts { // control flow analysis an opportunity to narrow it further. For example, for a reference of a type // parameter type 'T extends string | undefined' with a contextual type 'string', we substitute // 'string | undefined' to give control flow analysis the opportunity to narrow to type 'string'. - const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) && - someType(type, isGenericTypeWithUnionConstraint) && - (isConstraintPosition(type, reference) || hasContextualTypeWithNoGenericTypes(reference, checkMode)); - return substituteConstraints ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOrType(t) : t) : type; + if (checkMode && checkMode & CheckMode.Inferential) { + return type; + } + + let contextualType: Type | undefined; + // If we aren't in a constraint position, or we can't find a contextual type, or the contextual type indicates + // that the type in question may be a direct inference source, then don't do anything special. + if (!isConstraintPosition(type, reference) && !(contextualType = tryGetContextualTypeWithNoGenericTypes(reference, checkMode))) { + return type; + } + + const substituteConstraints = + // When we have a type parameter constrained to a union type, we can typically narrow to get better results. + someType(type, isGenericTypeWithUnionConstraint) || + // When the contextual type is 'unknown', we may need to narrow for compatibility with non-null targets. + // This allows some parity with a constraint of '{} | null | undefined'. + (type.flags & TypeFlags.Instantiable) && contextualType && isEmptyObjectType(contextualType); + + return substituteConstraints ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t) : type; } function isExportOrExportExpression(location: Node) { From df3766de9d9be733e60ea1f48e8bfc6b735337da Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 28 Apr 2022 00:43:57 +0000 Subject: [PATCH 4/6] Accepted baselines. --- .../conditionalTypeDoesntSpinForever.types | 2 +- ...onditionalTypesExcessProperties.errors.txt | 16 +++--- .../conditionalTypesExcessProperties.types | 16 +++--- .../constructorReturningAPrimitive.types | 2 +- ...ownToObjects(strictnullchecks=false).types | 16 +++--- ...nownToObjects(strictnullchecks=true).types | 16 +++--- ...InGetTextOfComputedPropertyName.errors.txt | 36 ++++++++++++ .../esNextWeakRefs_IterableWeakMap.types | 2 +- ...UnboundedTypeParamAssignability.errors.txt | 5 +- ...nericUnboundedTypeParamAssignability.types | 2 +- .../keyofAndIndexedAccess.errors.txt | 56 ++++++------------- .../reference/keyofAndIndexedAccess.types | 28 +++++----- .../logicalOrOperatorWithTypeParameters.types | 18 +++--- .../reference/mappedTypeConstraints2.types | 2 +- .../nonPrimitiveAndTypeVariables.errors.txt | 4 +- .../nonPrimitiveAndTypeVariables.types | 2 +- .../nonPrimitiveInGeneric.errors.txt | 4 +- .../reference/nonPrimitiveInGeneric.types | 6 +- .../reference/objectRestNegative.errors.txt | 5 +- .../reference/unknownType1.errors.txt | 23 +++----- tests/baselines/reference/unknownType1.types | 8 +-- 21 files changed, 138 insertions(+), 131 deletions(-) create mode 100644 tests/baselines/reference/crashInGetTextOfComputedPropertyName.errors.txt diff --git a/tests/baselines/reference/conditionalTypeDoesntSpinForever.types b/tests/baselines/reference/conditionalTypeDoesntSpinForever.types index c1eee6deff83f..0865bdaf1ba7b 100644 --- a/tests/baselines/reference/conditionalTypeDoesntSpinForever.types +++ b/tests/baselines/reference/conditionalTypeDoesntSpinForever.types @@ -413,7 +413,7 @@ export enum PubSubRecordIsStoredInRedisAsA { >Object.keys : { (o: object): string[]; (o: {}): string[]; } >Object : ObjectConstructor >keys : { (o: object): string[]; (o: {}): string[]; } ->soFar : SO_FAR +>soFar : unknown hasField: (fieldName: string | number | symbol) => fieldName in soFar >hasField : (fieldName: string | number | symbol) => boolean diff --git a/tests/baselines/reference/conditionalTypesExcessProperties.errors.txt b/tests/baselines/reference/conditionalTypesExcessProperties.errors.txt index 24669d3426d93..5d827141cb63c 100644 --- a/tests/baselines/reference/conditionalTypesExcessProperties.errors.txt +++ b/tests/baselines/reference/conditionalTypesExcessProperties.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(8,5): error TS2322: Type '{ test: string; arg: A; }' is not assignable to type 'Something'. - Type '{ test: string; arg: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. -tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(9,5): error TS2322: Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'Something'. - Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. +tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(8,5): error TS2322: Type '{ test: string; arg: object; }' is not assignable to type 'Something'. + Type '{ test: string; arg: object; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. +tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(9,5): error TS2322: Type '{ test: string; arg: object; arr: A; }' is not assignable to type 'Something'. + Type '{ test: string; arg: object; arr: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. ==== tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts (2 errors) ==== @@ -14,11 +14,11 @@ tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(9, function testFunc2(a: A, sa: Something) { sa = { test: 'hi', arg: a }; // not excess (but currently still not assignable) ~~ -!!! error TS2322: Type '{ test: string; arg: A; }' is not assignable to type 'Something'. -!!! error TS2322: Type '{ test: string; arg: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. +!!! error TS2322: Type '{ test: string; arg: object; }' is not assignable to type 'Something'. +!!! error TS2322: Type '{ test: string; arg: object; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. sa = { test: 'bye', arg: a, arr: a } // excess ~~ -!!! error TS2322: Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'Something'. -!!! error TS2322: Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. +!!! error TS2322: Type '{ test: string; arg: object; arr: A; }' is not assignable to type 'Something'. +!!! error TS2322: Type '{ test: string; arg: object; arr: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. } \ No newline at end of file diff --git a/tests/baselines/reference/conditionalTypesExcessProperties.types b/tests/baselines/reference/conditionalTypesExcessProperties.types index ad1be1146ce05..46cd0d4ed35fc 100644 --- a/tests/baselines/reference/conditionalTypesExcessProperties.types +++ b/tests/baselines/reference/conditionalTypesExcessProperties.types @@ -18,22 +18,22 @@ function testFunc2(a: A, sa: Something) { >sa : Something sa = { test: 'hi', arg: a }; // not excess (but currently still not assignable) ->sa = { test: 'hi', arg: a } : { test: string; arg: A; } +>sa = { test: 'hi', arg: a } : { test: string; arg: object; } >sa : Something ->{ test: 'hi', arg: a } : { test: string; arg: A; } +>{ test: 'hi', arg: a } : { test: string; arg: object; } >test : string >'hi' : "hi" ->arg : A ->a : A +>arg : object +>a : object sa = { test: 'bye', arg: a, arr: a } // excess ->sa = { test: 'bye', arg: a, arr: a } : { test: string; arg: A; arr: A; } +>sa = { test: 'bye', arg: a, arr: a } : { test: string; arg: object; arr: A; } >sa : Something ->{ test: 'bye', arg: a, arr: a } : { test: string; arg: A; arr: A; } +>{ test: 'bye', arg: a, arr: a } : { test: string; arg: object; arr: A; } >test : string >'bye' : "bye" ->arg : A ->a : A +>arg : object +>a : object >arr : A >a : A } diff --git a/tests/baselines/reference/constructorReturningAPrimitive.types b/tests/baselines/reference/constructorReturningAPrimitive.types index 2bd826d33b91a..f8ecc3901c00b 100644 --- a/tests/baselines/reference/constructorReturningAPrimitive.types +++ b/tests/baselines/reference/constructorReturningAPrimitive.types @@ -24,7 +24,7 @@ class B { >x : T return x; ->x : T +>x : unknown } } diff --git a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).types b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).types index b5800e2bb7d19..86668ece67517 100644 --- a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).types +++ b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).types @@ -56,12 +56,12 @@ namespace implicitConstraints { >keysOfEmptyObject(a).length : number >keysOfEmptyObject(a) : string[] >keysOfEmptyObject : (o: {}) => string[] ->a : T +>a : object >length : number >keysOfEmptyObject(b).length : number >keysOfEmptyObject(b) : string[] >keysOfEmptyObject : (o: {}) => string[] ->b : T +>b : object >length : number return [a, b]; @@ -119,12 +119,12 @@ namespace implicitConstraints { >keysOfNonPrimitive(a).length : number >keysOfNonPrimitive(a) : string[] >keysOfNonPrimitive : (o: object) => string[] ->a : T +>a : object >length : number >keysOfNonPrimitive(b).length : number >keysOfNonPrimitive(b) : string[] >keysOfNonPrimitive : (o: object) => string[] ->b : T +>b : object >length : number return [a, b]; @@ -187,12 +187,12 @@ namespace explicitConstraintsOfUnknown { >keysOfEmptyObject(a).length : number >keysOfEmptyObject(a) : string[] >keysOfEmptyObject : (o: {}) => string[] ->a : T +>a : object >length : number >keysOfEmptyObject(b).length : number >keysOfEmptyObject(b) : string[] >keysOfEmptyObject : (o: {}) => string[] ->b : T +>b : object >length : number return [a, b]; @@ -250,12 +250,12 @@ namespace explicitConstraintsOfUnknown { >keysOfNonPrimitive(a).length : number >keysOfNonPrimitive(a) : string[] >keysOfNonPrimitive : (o: object) => string[] ->a : T +>a : object >length : number >keysOfNonPrimitive(b).length : number >keysOfNonPrimitive(b) : string[] >keysOfNonPrimitive : (o: object) => string[] ->b : T +>b : object >length : number return [a, b]; diff --git a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).types b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).types index b5800e2bb7d19..86668ece67517 100644 --- a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).types +++ b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).types @@ -56,12 +56,12 @@ namespace implicitConstraints { >keysOfEmptyObject(a).length : number >keysOfEmptyObject(a) : string[] >keysOfEmptyObject : (o: {}) => string[] ->a : T +>a : object >length : number >keysOfEmptyObject(b).length : number >keysOfEmptyObject(b) : string[] >keysOfEmptyObject : (o: {}) => string[] ->b : T +>b : object >length : number return [a, b]; @@ -119,12 +119,12 @@ namespace implicitConstraints { >keysOfNonPrimitive(a).length : number >keysOfNonPrimitive(a) : string[] >keysOfNonPrimitive : (o: object) => string[] ->a : T +>a : object >length : number >keysOfNonPrimitive(b).length : number >keysOfNonPrimitive(b) : string[] >keysOfNonPrimitive : (o: object) => string[] ->b : T +>b : object >length : number return [a, b]; @@ -187,12 +187,12 @@ namespace explicitConstraintsOfUnknown { >keysOfEmptyObject(a).length : number >keysOfEmptyObject(a) : string[] >keysOfEmptyObject : (o: {}) => string[] ->a : T +>a : object >length : number >keysOfEmptyObject(b).length : number >keysOfEmptyObject(b) : string[] >keysOfEmptyObject : (o: {}) => string[] ->b : T +>b : object >length : number return [a, b]; @@ -250,12 +250,12 @@ namespace explicitConstraintsOfUnknown { >keysOfNonPrimitive(a).length : number >keysOfNonPrimitive(a) : string[] >keysOfNonPrimitive : (o: object) => string[] ->a : T +>a : object >length : number >keysOfNonPrimitive(b).length : number >keysOfNonPrimitive(b) : string[] >keysOfNonPrimitive : (o: object) => string[] ->b : T +>b : object >length : number return [a, b]; diff --git a/tests/baselines/reference/crashInGetTextOfComputedPropertyName.errors.txt b/tests/baselines/reference/crashInGetTextOfComputedPropertyName.errors.txt new file mode 100644 index 0000000000000..4997400674cf3 --- /dev/null +++ b/tests/baselines/reference/crashInGetTextOfComputedPropertyName.errors.txt @@ -0,0 +1,36 @@ +tests/cases/compiler/crashInGetTextOfComputedPropertyName.ts(23,24): error TS2525: Initializer provides no value for this binding element and the binding element has no default value. + + +==== tests/cases/compiler/crashInGetTextOfComputedPropertyName.ts (1 errors) ==== + // https://github.com/Microsoft/TypeScript/issues/29006 + export interface A { type: 'a' } + export interface B { type: 'b' } + export type AB = A | B + + const itemId = 'some-id' + + // --- test on first level --- + const items: { [id: string]: AB } = {} + const { [itemId]: itemOk1 } = items + typeof itemOk1 // pass + + // --- test on second level --- + interface ObjWithItems { + items: {[s: string]: AB} + } + const objWithItems: ObjWithItems = { items: {}} + + const itemOk2 = objWithItems.items[itemId] + typeof itemOk2 // pass + + const { + items: { [itemId]: itemWithTSError } = {} /*happens when default value is provided*/ + ~~~~~~~~~~~~~~~ +!!! error TS2525: Initializer provides no value for this binding element and the binding element has no default value. + } = objWithItems + + // in order to re-produce the error, uncomment next line: + typeof itemWithTSError // :( + + // will result in: + // Error from compilation: TypeError: Cannot read property 'charCodeAt' of undefined TypeError: Cannot read property 'charCodeAt' of undefined \ No newline at end of file diff --git a/tests/baselines/reference/esNextWeakRefs_IterableWeakMap.types b/tests/baselines/reference/esNextWeakRefs_IterableWeakMap.types index 79e54575127f7..010b7773b2b77 100644 --- a/tests/baselines/reference/esNextWeakRefs_IterableWeakMap.types +++ b/tests/baselines/reference/esNextWeakRefs_IterableWeakMap.types @@ -134,7 +134,7 @@ export class IterableWeakMap implements WeakMap { >this.#finalizationGroup : FinalizationRegistry<{ readonly ref: WeakRef; readonly set: Set>; }> >this : this >register : (target: object, heldValue: { readonly ref: WeakRef; readonly set: Set>; }, unregisterToken?: object | undefined) => void ->key : K +>key : object >{ set: this.#refSet, ref, } : { set: Set>; ref: WeakRef; } set: this.#refSet, diff --git a/tests/baselines/reference/genericUnboundedTypeParamAssignability.errors.txt b/tests/baselines/reference/genericUnboundedTypeParamAssignability.errors.txt index 6d7b87ebd3351..aaf5c4eed32e2 100644 --- a/tests/baselines/reference/genericUnboundedTypeParamAssignability.errors.txt +++ b/tests/baselines/reference/genericUnboundedTypeParamAssignability.errors.txt @@ -1,5 +1,5 @@ tests/cases/compiler/genericUnboundedTypeParamAssignability.ts(2,5): error TS2339: Property 'toString' does not exist on type 'T'. -tests/cases/compiler/genericUnboundedTypeParamAssignability.ts(15,6): error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. +tests/cases/compiler/genericUnboundedTypeParamAssignability.ts(15,6): error TS2345: Argument of type 'unknown' is not assignable to parameter of type '{}'. tests/cases/compiler/genericUnboundedTypeParamAssignability.ts(16,6): error TS2345: Argument of type 'T' is not assignable to parameter of type 'Record'. tests/cases/compiler/genericUnboundedTypeParamAssignability.ts(17,5): error TS2339: Property 'toString' does not exist on type 'T'. @@ -23,8 +23,7 @@ tests/cases/compiler/genericUnboundedTypeParamAssignability.ts(17,5): error TS23 f1(t); f2(t); // error in strict, unbounded T doesn't satisfy the constraint ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. -!!! related TS2208 tests/cases/compiler/genericUnboundedTypeParamAssignability.ts:13:15: This type parameter probably needs an `extends object` constraint. +!!! error TS2345: Argument of type 'unknown' is not assignable to parameter of type '{}'. f3(t); // error in strict, unbounded T doesn't satisfy the constraint ~ !!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'Record'. diff --git a/tests/baselines/reference/genericUnboundedTypeParamAssignability.types b/tests/baselines/reference/genericUnboundedTypeParamAssignability.types index 74136a19382a6..a3d95014eccc7 100644 --- a/tests/baselines/reference/genericUnboundedTypeParamAssignability.types +++ b/tests/baselines/reference/genericUnboundedTypeParamAssignability.types @@ -44,7 +44,7 @@ function user(t: T) { f2(t); // error in strict, unbounded T doesn't satisfy the constraint >f2(t) : void >f2 : (o: T) => void ->t : T +>t : unknown f3(t); // error in strict, unbounded T doesn't satisfy the constraint >f3(t) : void diff --git a/tests/baselines/reference/keyofAndIndexedAccess.errors.txt b/tests/baselines/reference/keyofAndIndexedAccess.errors.txt index f5c436bbf1dc2..a2a837fdfe4c0 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.errors.txt +++ b/tests/baselines/reference/keyofAndIndexedAccess.errors.txt @@ -1,22 +1,11 @@ -tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(316,5): error TS2322: Type 'T' is not assignable to type '{}'. -tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(317,5): error TS2322: Type 'T[keyof T]' is not assignable to type '{}'. - Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{}'. - Type 'T[string]' is not assignable to type '{}'. -tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(318,5): error TS2322: Type 'T[K]' is not assignable to type '{}'. - Type 'T[keyof T]' is not assignable to type '{}'. -tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(323,5): error TS2322: Type 'T' is not assignable to type '{} | null | undefined'. -tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(324,5): error TS2322: Type 'T[keyof T]' is not assignable to type '{} | null | undefined'. - Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{} | null | undefined'. - Type 'T[string]' is not assignable to type '{} | null | undefined'. -tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(325,5): error TS2322: Type 'T[K]' is not assignable to type '{} | null | undefined'. - Type 'T[keyof T]' is not assignable to type '{} | null | undefined'. -tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(611,33): error TS2345: Argument of type 'T[K]' is not assignable to parameter of type '{} | null | undefined'. - Type 'T[keyof T]' is not assignable to type '{} | null | undefined'. - Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{} | null | undefined'. - Type 'T[string]' is not assignable to type '{} | null | undefined'. -tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(619,13): error TS2322: Type 'T[keyof T]' is not assignable to type '{} | null | undefined'. - Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{} | null | undefined'. - Type 'T[string]' is not assignable to type '{} | null | undefined'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(316,5): error TS2322: Type 'unknown' is not assignable to type '{}'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(317,5): error TS2322: Type 'unknown' is not assignable to type '{}'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(318,5): error TS2322: Type 'unknown' is not assignable to type '{}'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(323,5): error TS2322: Type 'unknown' is not assignable to type '{} | null | undefined'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(324,5): error TS2322: Type 'unknown' is not assignable to type '{} | null | undefined'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(325,5): error TS2322: Type 'unknown' is not assignable to type '{} | null | undefined'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(611,33): error TS2345: Argument of type 'unknown' is not assignable to parameter of type '{} | null | undefined'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(619,13): error TS2322: Type 'unknown' is not assignable to type '{} | null | undefined'. ==== tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts (8 errors) ==== @@ -337,34 +326,26 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(619,13): error TS23 let a: {}; a = x; ~ -!!! error TS2322: Type 'T' is not assignable to type '{}'. -!!! related TS2208 tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts:314:14: This type parameter probably needs an `extends object` constraint. +!!! error TS2322: Type 'unknown' is not assignable to type '{}'. a = y; ~ -!!! error TS2322: Type 'T[keyof T]' is not assignable to type '{}'. -!!! error TS2322: Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{}'. -!!! error TS2322: Type 'T[string]' is not assignable to type '{}'. +!!! error TS2322: Type 'unknown' is not assignable to type '{}'. a = z; ~ -!!! error TS2322: Type 'T[K]' is not assignable to type '{}'. -!!! error TS2322: Type 'T[keyof T]' is not assignable to type '{}'. +!!! error TS2322: Type 'unknown' is not assignable to type '{}'. } function f92(x: T, y: T[keyof T], z: T[K]) { let a: {} | null | undefined; a = x; ~ -!!! error TS2322: Type 'T' is not assignable to type '{} | null | undefined'. -!!! related TS2208 tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts:321:14: This type parameter probably needs an `extends object` constraint. +!!! error TS2322: Type 'unknown' is not assignable to type '{} | null | undefined'. a = y; ~ -!!! error TS2322: Type 'T[keyof T]' is not assignable to type '{} | null | undefined'. -!!! error TS2322: Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{} | null | undefined'. -!!! error TS2322: Type 'T[string]' is not assignable to type '{} | null | undefined'. +!!! error TS2322: Type 'unknown' is not assignable to type '{} | null | undefined'. a = z; ~ -!!! error TS2322: Type 'T[K]' is not assignable to type '{} | null | undefined'. -!!! error TS2322: Type 'T[keyof T]' is not assignable to type '{} | null | undefined'. +!!! error TS2322: Type 'unknown' is not assignable to type '{} | null | undefined'. } // Repros from #12011 @@ -652,10 +633,7 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(619,13): error TS23 function fn(o: T, k: K) { take<{} | null | undefined>(o[k]); ~~~~ -!!! error TS2345: Argument of type 'T[K]' is not assignable to parameter of type '{} | null | undefined'. -!!! error TS2345: Type 'T[keyof T]' is not assignable to type '{} | null | undefined'. -!!! error TS2345: Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{} | null | undefined'. -!!! error TS2345: Type 'T[string]' is not assignable to type '{} | null | undefined'. +!!! error TS2345: Argument of type 'unknown' is not assignable to parameter of type '{} | null | undefined'. take(o[k]); } @@ -665,9 +643,7 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(619,13): error TS23 foo(x: T[keyof T]) { let y: {} | undefined | null = x; ~ -!!! error TS2322: Type 'T[keyof T]' is not assignable to type '{} | null | undefined'. -!!! error TS2322: Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{} | null | undefined'. -!!! error TS2322: Type 'T[string]' is not assignable to type '{} | null | undefined'. +!!! error TS2322: Type 'unknown' is not assignable to type '{} | null | undefined'. } } diff --git a/tests/baselines/reference/keyofAndIndexedAccess.types b/tests/baselines/reference/keyofAndIndexedAccess.types index fc4603b997ff7..7e71ca34d4926 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.types +++ b/tests/baselines/reference/keyofAndIndexedAccess.types @@ -1268,19 +1268,19 @@ function f91(x: T, y: T[keyof T], z: T[K]) { >a : {} a = x; ->a = x : T +>a = x : unknown >a : {} ->x : T +>x : unknown a = y; ->a = y : T[keyof T] +>a = y : unknown >a : {} ->y : T[keyof T] +>y : unknown a = z; ->a = z : T[K] +>a = z : unknown >a : {} ->z : T[K] +>z : unknown } function f92(x: T, y: T[keyof T], z: T[K]) { @@ -1294,19 +1294,19 @@ function f92(x: T, y: T[keyof T], z: T[K]) { >null : null a = x; ->a = x : T +>a = x : unknown >a : {} | null | undefined ->x : T +>x : unknown a = y; ->a = y : T[keyof T] +>a = y : unknown >a : {} | null | undefined ->y : T[keyof T] +>y : unknown a = z; ->a = z : T[K] +>a = z : unknown >a : {} | null | undefined ->z : T[K] +>z : unknown } // Repros from #12011 @@ -2065,7 +2065,7 @@ function fn(o: T, k: K) { >take<{} | null | undefined>(o[k]) : void >take : (p: T) => void >null : null ->o[k] : T[K] +>o[k] : unknown >o : T >k : K @@ -2089,7 +2089,7 @@ class Unbounded { let y: {} | undefined | null = x; >y : {} | null | undefined >null : null ->x : T[keyof T] +>x : unknown } } diff --git a/tests/baselines/reference/logicalOrOperatorWithTypeParameters.types b/tests/baselines/reference/logicalOrOperatorWithTypeParameters.types index bae889230c5a6..2e1af26611168 100644 --- a/tests/baselines/reference/logicalOrOperatorWithTypeParameters.types +++ b/tests/baselines/reference/logicalOrOperatorWithTypeParameters.types @@ -24,9 +24,9 @@ function fn1(t: T, u: U) { var r4: {} = t || u; >r4 : {} ->t || u : T | U ->t : T ->u : U +>t || u : unknown +>t : unknown +>u : unknown } function fn2(t: T, u: U, v: V) { @@ -62,9 +62,9 @@ function fn2(t: T, u: U, v: V) { var r6: {} = u || v; >r6 : {} ->u || v : U | V ->u : U ->v : V +>u || v : unknown +>u : unknown +>v : unknown //var r7: T = u || v; } @@ -86,9 +86,9 @@ function fn3r2 : {} ->t || u : T | U ->t : T ->u : U +>t || u : { a: string; b: string; } | { a: string; b: number; } +>t : { a: string; b: string; } +>u : { a: string; b: number; } var r3 = t || { a: '' }; >r3 : T | { a: string; } diff --git a/tests/baselines/reference/mappedTypeConstraints2.types b/tests/baselines/reference/mappedTypeConstraints2.types index 534e02c8518db..927b58a24cd99 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.types +++ b/tests/baselines/reference/mappedTypeConstraints2.types @@ -96,7 +96,7 @@ function validate(obj: T, bounds: NumericBoundsOf) { >Object.entries : { (o: { [s: string]: T; } | ArrayLike): [string, T][]; (o: {}): [string, any][]; } >Object : ObjectConstructor >entries : { (o: { [s: string]: T; } | ArrayLike): [string, T][]; (o: {}): [string, any][]; } ->obj : T +>obj : object const boundsForKey = bounds[key as keyof NumericBoundsOf]; >boundsForKey : NumericBoundsOf[keyof NumericBoundsOf] diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt b/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt index c3e8acb3923ab..c20642f2d2812 100644 --- a/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts(10,9): error TS2322: Type 'T' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts(10,9): error TS2322: Type 'unknown' is not assignable to type 'object'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts(11,9): error TS2322: Type 'T' is not assignable to type 'object | U'. @@ -14,7 +14,7 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts(11,9) function foo(x: T) { let a: object = x; // Error ~ -!!! error TS2322: Type 'T' is not assignable to type 'object'. +!!! error TS2322: Type 'unknown' is not assignable to type 'object'. let b: U | object = x; // Error ~ !!! error TS2322: Type 'T' is not assignable to type 'object | U'. diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.types b/tests/baselines/reference/nonPrimitiveAndTypeVariables.types index 8559a7bab0c18..52d330c866257 100644 --- a/tests/baselines/reference/nonPrimitiveAndTypeVariables.types +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.types @@ -27,7 +27,7 @@ function foo(x: T) { let a: object = x; // Error >a : object ->x : T +>x : unknown let b: U | object = x; // Error >b : object | U diff --git a/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt b/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt index 5cc7d3664b080..aeea457fae335 100644 --- a/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt +++ b/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(2,9): error TS2322: Type 'T' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(2,9): error TS2322: Type 'unknown' is not assignable to type 'object'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(9,17): error TS2345: Argument of type 'number' is not assignable to parameter of type 'object'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(10,17): error TS2345: Argument of type 'string' is not assignable to parameter of type 'object'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(18,7): error TS2345: Argument of type 'number' is not assignable to parameter of type 'object'. @@ -12,7 +12,7 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(34,14): erro function generic(t: T) { var o: object = t; // expect error ~ -!!! error TS2322: Type 'T' is not assignable to type 'object'. +!!! error TS2322: Type 'unknown' is not assignable to type 'object'. } var a = {}; var b = "42"; diff --git a/tests/baselines/reference/nonPrimitiveInGeneric.types b/tests/baselines/reference/nonPrimitiveInGeneric.types index f46f0e0e7ef02..1467e24bc7da5 100644 --- a/tests/baselines/reference/nonPrimitiveInGeneric.types +++ b/tests/baselines/reference/nonPrimitiveInGeneric.types @@ -5,7 +5,7 @@ function generic(t: T) { var o: object = t; // expect error >o : object ->t : T +>t : unknown } var a = {}; >a : {} @@ -41,7 +41,7 @@ function bound(t: T) { var o: object = t; // ok >o : object ->t : T +>t : object } bound({}); @@ -89,7 +89,7 @@ function bound3(t: T) { var o: object = t; // ok >o : object ->t : T +>t : {} } interface Proxy {} diff --git a/tests/baselines/reference/objectRestNegative.errors.txt b/tests/baselines/reference/objectRestNegative.errors.txt index 42b25d137ef96..23247635b240b 100644 --- a/tests/baselines/reference/objectRestNegative.errors.txt +++ b/tests/baselines/reference/objectRestNegative.errors.txt @@ -5,10 +5,11 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(6,10): error TS2322: Ty tests/cases/conformance/types/rest/objectRestNegative.ts(9,31): error TS2462: A rest element must be last in a destructuring pattern. tests/cases/conformance/types/rest/objectRestNegative.ts(11,30): error TS7008: Member 'x' implicitly has an 'any' type. tests/cases/conformance/types/rest/objectRestNegative.ts(11,33): error TS7008: Member 'y' implicitly has an 'any' type. +tests/cases/conformance/types/rest/objectRestNegative.ts(17,6): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: The target of an object rest assignment must be a variable or a property access. -==== tests/cases/conformance/types/rest/objectRestNegative.ts (6 errors) ==== +==== tests/cases/conformance/types/rest/objectRestNegative.ts (7 errors) ==== let o = { a: 1, b: 'no' }; var { ...mustBeLast, a } = o; ~~~~~~~~~~ @@ -38,6 +39,8 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: Th let rest: { b: string } ({a, ...rest.b + rest.b} = o); + ~~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. ~~~~~~~~~~~~~~~ !!! error TS2701: The target of an object rest assignment must be a variable or a property access. \ No newline at end of file diff --git a/tests/baselines/reference/unknownType1.errors.txt b/tests/baselines/reference/unknownType1.errors.txt index 39d7a1feb5255..9e89361cb2478 100644 --- a/tests/baselines/reference/unknownType1.errors.txt +++ b/tests/baselines/reference/unknownType1.errors.txt @@ -15,8 +15,7 @@ tests/cases/conformance/types/unknown/unknownType1.ts(111,9): error TS2322: Type tests/cases/conformance/types/unknown/unknownType1.ts(112,9): error TS2322: Type 'unknown' is not assignable to type 'string[]'. tests/cases/conformance/types/unknown/unknownType1.ts(113,9): error TS2322: Type 'unknown' is not assignable to type '{}'. tests/cases/conformance/types/unknown/unknownType1.ts(114,9): error TS2322: Type 'unknown' is not assignable to type '{} | null | undefined'. -tests/cases/conformance/types/unknown/unknownType1.ts(120,9): error TS2322: Type 'T' is not assignable to type 'object'. - Type 'unknown' is not assignable to type 'object'. +tests/cases/conformance/types/unknown/unknownType1.ts(120,9): error TS2322: Type 'unknown' is not assignable to type 'object'. tests/cases/conformance/types/unknown/unknownType1.ts(128,5): error TS2322: Type 'number[]' is not assignable to type '{ [x: string]: unknown; }'. Index signature for type 'string' is missing in type 'number[]'. tests/cases/conformance/types/unknown/unknownType1.ts(129,5): error TS2322: Type 'number' is not assignable to type '{ [x: string]: unknown; }'. @@ -25,11 +24,9 @@ tests/cases/conformance/types/unknown/unknownType1.ts(144,29): error TS2698: Spr tests/cases/conformance/types/unknown/unknownType1.ts(150,17): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value. tests/cases/conformance/types/unknown/unknownType1.ts(156,14): error TS2700: Rest types may only be created from object types. tests/cases/conformance/types/unknown/unknownType1.ts(162,5): error TS2564: Property 'a' has no initializer and is not definitely assigned in the constructor. -tests/cases/conformance/types/unknown/unknownType1.ts(170,9): error TS2322: Type 'T' is not assignable to type '{}'. -tests/cases/conformance/types/unknown/unknownType1.ts(171,9): error TS2322: Type 'U' is not assignable to type '{}'. - Type 'unknown' is not assignable to type '{}'. -tests/cases/conformance/types/unknown/unknownType1.ts(181,5): error TS2322: Type 'T' is not assignable to type '{}'. - Type 'unknown' is not assignable to type '{}'. +tests/cases/conformance/types/unknown/unknownType1.ts(170,9): error TS2322: Type 'unknown' is not assignable to type '{}'. +tests/cases/conformance/types/unknown/unknownType1.ts(171,9): error TS2322: Type 'unknown' is not assignable to type '{}'. +tests/cases/conformance/types/unknown/unknownType1.ts(181,5): error TS2322: Type 'unknown' is not assignable to type '{}'. ==== tests/cases/conformance/types/unknown/unknownType1.ts (28 errors) ==== @@ -188,8 +185,7 @@ tests/cases/conformance/types/unknown/unknownType1.ts(181,5): error TS2322: Type function f23(x: T) { let y: object = x; // Error ~ -!!! error TS2322: Type 'T' is not assignable to type 'object'. -!!! error TS2322: Type 'unknown' is not assignable to type 'object'. +!!! error TS2322: Type 'unknown' is not assignable to type 'object'. } // Anything fresh but primitive assignable to { [x: string]: unknown } @@ -256,12 +252,10 @@ tests/cases/conformance/types/unknown/unknownType1.ts(181,5): error TS2322: Type function f30(t: T, u: U) { let x: {} = t; ~ -!!! error TS2322: Type 'T' is not assignable to type '{}'. -!!! related TS2208 tests/cases/conformance/types/unknown/unknownType1.ts:169:14: This type parameter probably needs an `extends object` constraint. +!!! error TS2322: Type 'unknown' is not assignable to type '{}'. let y: {} = u; ~ -!!! error TS2322: Type 'U' is not assignable to type '{}'. -!!! error TS2322: Type 'unknown' is not assignable to type '{}'. +!!! error TS2322: Type 'unknown' is not assignable to type '{}'. } // Repro from #26796 @@ -273,7 +267,6 @@ tests/cases/conformance/types/unknown/unknownType1.ts(181,5): error TS2322: Type function oops(arg: T): {} { return arg; // Error ~~~~~~~~~~~ -!!! error TS2322: Type 'T' is not assignable to type '{}'. -!!! error TS2322: Type 'unknown' is not assignable to type '{}'. +!!! error TS2322: Type 'unknown' is not assignable to type '{}'. } \ No newline at end of file diff --git a/tests/baselines/reference/unknownType1.types b/tests/baselines/reference/unknownType1.types index c6911e0bf3bdd..f83b3f7c84d91 100644 --- a/tests/baselines/reference/unknownType1.types +++ b/tests/baselines/reference/unknownType1.types @@ -339,7 +339,7 @@ function f23(x: T) { let y: object = x; // Error >y : object ->x : T +>x : unknown } // Anything fresh but primitive assignable to { [x: string]: unknown } @@ -469,11 +469,11 @@ function f30(t: T, u: U) { let x: {} = t; >x : {} ->t : T +>t : unknown let y: {} = u; >y : {} ->u : U +>u : unknown } // Repro from #26796 @@ -496,6 +496,6 @@ function oops(arg: T): {} { >arg : T return arg; // Error ->arg : T +>arg : unknown } From 17b7226ac1fad1d764cb5e4efdc29470e3f91206 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 28 Apr 2022 01:47:47 +0000 Subject: [PATCH 5/6] Change in logic, up-front check for instantiables. --- src/compiler/checker.ts | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ec7e398f1000d..1ffce28298667 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25460,25 +25460,41 @@ namespace ts { // control flow analysis an opportunity to narrow it further. For example, for a reference of a type // parameter type 'T extends string | undefined' with a contextual type 'string', we substitute // 'string | undefined' to give control flow analysis the opportunity to narrow to type 'string'. - if (checkMode && checkMode & CheckMode.Inferential) { + if (checkMode && (checkMode & CheckMode.Inferential)) { return type; } - let contextualType: Type | undefined; - // If we aren't in a constraint position, or we can't find a contextual type, or the contextual type indicates - // that the type in question may be a direct inference source, then don't do anything special. - if (!isConstraintPosition(type, reference) && !(contextualType = tryGetContextualTypeWithNoGenericTypes(reference, checkMode))) { + // Bail-out early if we don't have anything instantiable in the first place. + if (!someType(type, t => !!(t.flags & TypeFlags.Instantiable))) { return type; } + const hasGenericWithUnionConstraint = someType(type, isGenericTypeWithUnionConstraint); + // If we only care about the apparent types of a value's constraints, we should narrow based on the constraint. + if (hasGenericWithUnionConstraint && isConstraintPosition(type, reference)) { + return getTypeWithConstraintsSubstituted(); + } + + const contextualType = tryGetContextualTypeWithNoGenericTypes(reference, checkMode); + // If there's no contextual type, that's a signal that we don't need to perform any substitution. + // If there *is* a contextual type, but it has top-level type variables, then it's not appropriate to narrow on + // constraints since the original type may be inferred from. + if (!contextualType) { + return type; + } + + // When we have a type parameter constrained to a union type, or unknown, we can typically narrow on the constraint to get better results. const substituteConstraints = - // When we have a type parameter constrained to a union type, we can typically narrow to get better results. - someType(type, isGenericTypeWithUnionConstraint) || + hasGenericWithUnionConstraint || // When the contextual type is 'unknown', we may need to narrow for compatibility with non-null targets. // This allows some parity with a constraint of '{} | null | undefined'. - (type.flags & TypeFlags.Instantiable) && contextualType && isEmptyObjectType(contextualType); + (getBaseConstraintOfType(type) || unknownType) === unknownType && isEmptyObjectType(contextualType); + + return substituteConstraints ? getTypeWithConstraintsSubstituted() : type; - return substituteConstraints ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t) : type; + function getTypeWithConstraintsSubstituted() { + return mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t); + } } function isExportOrExportExpression(location: Node) { From 0ed8bffa3dda64c553f40b70b455e341c53ce3c6 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 28 Apr 2022 01:48:00 +0000 Subject: [PATCH 6/6] Accepted baselines. --- ...onditionalTypesExcessProperties.errors.txt | 16 ++-- .../conditionalTypesExcessProperties.types | 16 ++-- ...Objects(strictnullchecks=false).errors.txt | 77 --------------- ...oObjects(strictnullchecks=true).errors.txt | 93 ------------------- ...InGetTextOfComputedPropertyName.errors.txt | 36 ------- .../esNextWeakRefs_IterableWeakMap.types | 2 +- .../logicalOrOperatorWithTypeParameters.types | 6 +- .../reference/mappedTypeConstraints2.types | 2 +- .../reference/nonPrimitiveInGeneric.types | 4 +- .../reference/objectRestNegative.errors.txt | 5 +- 10 files changed, 24 insertions(+), 233 deletions(-) delete mode 100644 tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).errors.txt delete mode 100644 tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).errors.txt delete mode 100644 tests/baselines/reference/crashInGetTextOfComputedPropertyName.errors.txt diff --git a/tests/baselines/reference/conditionalTypesExcessProperties.errors.txt b/tests/baselines/reference/conditionalTypesExcessProperties.errors.txt index 5d827141cb63c..24669d3426d93 100644 --- a/tests/baselines/reference/conditionalTypesExcessProperties.errors.txt +++ b/tests/baselines/reference/conditionalTypesExcessProperties.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(8,5): error TS2322: Type '{ test: string; arg: object; }' is not assignable to type 'Something'. - Type '{ test: string; arg: object; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. -tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(9,5): error TS2322: Type '{ test: string; arg: object; arr: A; }' is not assignable to type 'Something'. - Type '{ test: string; arg: object; arr: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. +tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(8,5): error TS2322: Type '{ test: string; arg: A; }' is not assignable to type 'Something'. + Type '{ test: string; arg: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. +tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(9,5): error TS2322: Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'Something'. + Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. ==== tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts (2 errors) ==== @@ -14,11 +14,11 @@ tests/cases/conformance/types/conditional/conditionalTypesExcessProperties.ts(9, function testFunc2(a: A, sa: Something) { sa = { test: 'hi', arg: a }; // not excess (but currently still not assignable) ~~ -!!! error TS2322: Type '{ test: string; arg: object; }' is not assignable to type 'Something'. -!!! error TS2322: Type '{ test: string; arg: object; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. +!!! error TS2322: Type '{ test: string; arg: A; }' is not assignable to type 'Something'. +!!! error TS2322: Type '{ test: string; arg: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. sa = { test: 'bye', arg: a, arr: a } // excess ~~ -!!! error TS2322: Type '{ test: string; arg: object; arr: A; }' is not assignable to type 'Something'. -!!! error TS2322: Type '{ test: string; arg: object; arr: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. +!!! error TS2322: Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'Something'. +!!! error TS2322: Type '{ test: string; arg: A; arr: A; }' is not assignable to type 'A extends object ? { arg: A; } : { arg?: undefined; }'. } \ No newline at end of file diff --git a/tests/baselines/reference/conditionalTypesExcessProperties.types b/tests/baselines/reference/conditionalTypesExcessProperties.types index 46cd0d4ed35fc..ad1be1146ce05 100644 --- a/tests/baselines/reference/conditionalTypesExcessProperties.types +++ b/tests/baselines/reference/conditionalTypesExcessProperties.types @@ -18,22 +18,22 @@ function testFunc2(a: A, sa: Something) { >sa : Something sa = { test: 'hi', arg: a }; // not excess (but currently still not assignable) ->sa = { test: 'hi', arg: a } : { test: string; arg: object; } +>sa = { test: 'hi', arg: a } : { test: string; arg: A; } >sa : Something ->{ test: 'hi', arg: a } : { test: string; arg: object; } +>{ test: 'hi', arg: a } : { test: string; arg: A; } >test : string >'hi' : "hi" ->arg : object ->a : object +>arg : A +>a : A sa = { test: 'bye', arg: a, arr: a } // excess ->sa = { test: 'bye', arg: a, arr: a } : { test: string; arg: object; arr: A; } +>sa = { test: 'bye', arg: a, arr: a } : { test: string; arg: A; arr: A; } >sa : Something ->{ test: 'bye', arg: a, arr: a } : { test: string; arg: object; arr: A; } +>{ test: 'bye', arg: a, arr: a } : { test: string; arg: A; arr: A; } >test : string >'bye' : "bye" ->arg : object ->a : object +>arg : A +>a : A >arr : A >a : A } diff --git a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).errors.txt b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).errors.txt deleted file mode 100644 index 47a6bdefc27c4..0000000000000 --- a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=false).errors.txt +++ /dev/null @@ -1,77 +0,0 @@ -tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(25,32): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. -tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(25,65): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. -tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(54,32): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. - Type 'unknown' is not assignable to type 'object'. -tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(54,65): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. - - -==== tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts (4 errors) ==== - declare function keysOfEmptyObject(o: {}): string[]; - declare function keysOfNonPrimitive(o: object): string[]; - - namespace implicitConstraints { - export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { - if (typeof a !== "object" || typeof b !== "object" || !a || !b) { - return undefined; - } - if (Array.isArray(a) || Array.isArray(b)) { - return undefined; - } - if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { - return [a, b]; - } - return undefined; - } - - export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { - if (typeof a !== "object" || typeof b !== "object" || !a || !b) { - return undefined; - } - if (Array.isArray(a) || Array.isArray(b)) { - return undefined; - } - if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { - ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. - ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. - return [a, b]; - } - return undefined; - } - } - - // Explicit Constraints of 'unknown' - namespace explicitConstraintsOfUnknown { - export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { - if (typeof a !== "object" || typeof b !== "object" || !a || !b) { - return undefined; - } - if (Array.isArray(a) || Array.isArray(b)) { - return undefined; - } - if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { - return [a, b]; - } - return undefined; - } - - export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { - if (typeof a !== "object" || typeof b !== "object" || !a || !b) { - return undefined; - } - if (Array.isArray(a) || Array.isArray(b)) { - return undefined; - } - if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { - ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. -!!! error TS2345: Type 'unknown' is not assignable to type 'object'. - ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. - return [a, b]; - } - return undefined; - } - } - \ No newline at end of file diff --git a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).errors.txt b/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).errors.txt deleted file mode 100644 index a9aaada48f448..0000000000000 --- a/tests/baselines/reference/contextualNarrowingFromUnknownToObjects(strictnullchecks=true).errors.txt +++ /dev/null @@ -1,93 +0,0 @@ -tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(12,31): error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. -tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(12,63): error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. -tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(25,32): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. -tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(25,65): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. -tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(41,31): error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. - Type 'unknown' is not assignable to type '{}'. -tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(41,63): error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. -tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(54,32): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. - Type 'unknown' is not assignable to type 'object'. -tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts(54,65): error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. - - -==== tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts (8 errors) ==== - declare function keysOfEmptyObject(o: {}): string[]; - declare function keysOfNonPrimitive(o: object): string[]; - - namespace implicitConstraints { - export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { - if (typeof a !== "object" || typeof b !== "object" || !a || !b) { - return undefined; - } - if (Array.isArray(a) || Array.isArray(b)) { - return undefined; - } - if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { - ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. -!!! related TS2208 tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts:5:55: This type parameter probably needs an `extends object` constraint. - ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. -!!! related TS2208 tests/cases/compiler/contextualNarrowingFromUnknownToObjects.ts:5:55: This type parameter probably needs an `extends object` constraint. - return [a, b]; - } - return undefined; - } - - export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { - if (typeof a !== "object" || typeof b !== "object" || !a || !b) { - return undefined; - } - if (Array.isArray(a) || Array.isArray(b)) { - return undefined; - } - if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { - ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. - ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. - return [a, b]; - } - return undefined; - } - } - - // Explicit Constraints of 'unknown' - namespace explicitConstraintsOfUnknown { - export function keyLengthsEqualUsingEmptyObjectFn(a: T, b: T): [T, T] | undefined { - if (typeof a !== "object" || typeof b !== "object" || !a || !b) { - return undefined; - } - if (Array.isArray(a) || Array.isArray(b)) { - return undefined; - } - if (keysOfEmptyObject(a).length !== keysOfEmptyObject(b).length) { - ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. -!!! error TS2345: Type 'unknown' is not assignable to type '{}'. - ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type '{}'. - return [a, b]; - } - return undefined; - } - - export function keyLengthsEqualUsingNonPrimitiveFn(a: T, b: T): [T, T] | undefined { - if (typeof a !== "object" || typeof b !== "object" || !a || !b) { - return undefined; - } - if (Array.isArray(a) || Array.isArray(b)) { - return undefined; - } - if (keysOfNonPrimitive(a).length !== keysOfNonPrimitive(b).length) { - ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. -!!! error TS2345: Type 'unknown' is not assignable to type 'object'. - ~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'object'. - return [a, b]; - } - return undefined; - } - } - \ No newline at end of file diff --git a/tests/baselines/reference/crashInGetTextOfComputedPropertyName.errors.txt b/tests/baselines/reference/crashInGetTextOfComputedPropertyName.errors.txt deleted file mode 100644 index 4997400674cf3..0000000000000 --- a/tests/baselines/reference/crashInGetTextOfComputedPropertyName.errors.txt +++ /dev/null @@ -1,36 +0,0 @@ -tests/cases/compiler/crashInGetTextOfComputedPropertyName.ts(23,24): error TS2525: Initializer provides no value for this binding element and the binding element has no default value. - - -==== tests/cases/compiler/crashInGetTextOfComputedPropertyName.ts (1 errors) ==== - // https://github.com/Microsoft/TypeScript/issues/29006 - export interface A { type: 'a' } - export interface B { type: 'b' } - export type AB = A | B - - const itemId = 'some-id' - - // --- test on first level --- - const items: { [id: string]: AB } = {} - const { [itemId]: itemOk1 } = items - typeof itemOk1 // pass - - // --- test on second level --- - interface ObjWithItems { - items: {[s: string]: AB} - } - const objWithItems: ObjWithItems = { items: {}} - - const itemOk2 = objWithItems.items[itemId] - typeof itemOk2 // pass - - const { - items: { [itemId]: itemWithTSError } = {} /*happens when default value is provided*/ - ~~~~~~~~~~~~~~~ -!!! error TS2525: Initializer provides no value for this binding element and the binding element has no default value. - } = objWithItems - - // in order to re-produce the error, uncomment next line: - typeof itemWithTSError // :( - - // will result in: - // Error from compilation: TypeError: Cannot read property 'charCodeAt' of undefined TypeError: Cannot read property 'charCodeAt' of undefined \ No newline at end of file diff --git a/tests/baselines/reference/esNextWeakRefs_IterableWeakMap.types b/tests/baselines/reference/esNextWeakRefs_IterableWeakMap.types index 010b7773b2b77..79e54575127f7 100644 --- a/tests/baselines/reference/esNextWeakRefs_IterableWeakMap.types +++ b/tests/baselines/reference/esNextWeakRefs_IterableWeakMap.types @@ -134,7 +134,7 @@ export class IterableWeakMap implements WeakMap { >this.#finalizationGroup : FinalizationRegistry<{ readonly ref: WeakRef; readonly set: Set>; }> >this : this >register : (target: object, heldValue: { readonly ref: WeakRef; readonly set: Set>; }, unregisterToken?: object | undefined) => void ->key : object +>key : K >{ set: this.#refSet, ref, } : { set: Set>; ref: WeakRef; } set: this.#refSet, diff --git a/tests/baselines/reference/logicalOrOperatorWithTypeParameters.types b/tests/baselines/reference/logicalOrOperatorWithTypeParameters.types index 2e1af26611168..ad8e5a3def0c5 100644 --- a/tests/baselines/reference/logicalOrOperatorWithTypeParameters.types +++ b/tests/baselines/reference/logicalOrOperatorWithTypeParameters.types @@ -86,9 +86,9 @@ function fn3r2 : {} ->t || u : { a: string; b: string; } | { a: string; b: number; } ->t : { a: string; b: string; } ->u : { a: string; b: number; } +>t || u : T | U +>t : T +>u : U var r3 = t || { a: '' }; >r3 : T | { a: string; } diff --git a/tests/baselines/reference/mappedTypeConstraints2.types b/tests/baselines/reference/mappedTypeConstraints2.types index 927b58a24cd99..534e02c8518db 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.types +++ b/tests/baselines/reference/mappedTypeConstraints2.types @@ -96,7 +96,7 @@ function validate(obj: T, bounds: NumericBoundsOf) { >Object.entries : { (o: { [s: string]: T; } | ArrayLike): [string, T][]; (o: {}): [string, any][]; } >Object : ObjectConstructor >entries : { (o: { [s: string]: T; } | ArrayLike): [string, T][]; (o: {}): [string, any][]; } ->obj : object +>obj : T const boundsForKey = bounds[key as keyof NumericBoundsOf]; >boundsForKey : NumericBoundsOf[keyof NumericBoundsOf] diff --git a/tests/baselines/reference/nonPrimitiveInGeneric.types b/tests/baselines/reference/nonPrimitiveInGeneric.types index 1467e24bc7da5..3a25010d82668 100644 --- a/tests/baselines/reference/nonPrimitiveInGeneric.types +++ b/tests/baselines/reference/nonPrimitiveInGeneric.types @@ -41,7 +41,7 @@ function bound(t: T) { var o: object = t; // ok >o : object ->t : object +>t : T } bound({}); @@ -89,7 +89,7 @@ function bound3(t: T) { var o: object = t; // ok >o : object ->t : {} +>t : T } interface Proxy {} diff --git a/tests/baselines/reference/objectRestNegative.errors.txt b/tests/baselines/reference/objectRestNegative.errors.txt index 23247635b240b..42b25d137ef96 100644 --- a/tests/baselines/reference/objectRestNegative.errors.txt +++ b/tests/baselines/reference/objectRestNegative.errors.txt @@ -5,11 +5,10 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(6,10): error TS2322: Ty tests/cases/conformance/types/rest/objectRestNegative.ts(9,31): error TS2462: A rest element must be last in a destructuring pattern. tests/cases/conformance/types/rest/objectRestNegative.ts(11,30): error TS7008: Member 'x' implicitly has an 'any' type. tests/cases/conformance/types/rest/objectRestNegative.ts(11,33): error TS7008: Member 'y' implicitly has an 'any' type. -tests/cases/conformance/types/rest/objectRestNegative.ts(17,6): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: The target of an object rest assignment must be a variable or a property access. -==== tests/cases/conformance/types/rest/objectRestNegative.ts (7 errors) ==== +==== tests/cases/conformance/types/rest/objectRestNegative.ts (6 errors) ==== let o = { a: 1, b: 'no' }; var { ...mustBeLast, a } = o; ~~~~~~~~~~ @@ -39,8 +38,6 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: Th let rest: { b: string } ({a, ...rest.b + rest.b} = o); - ~~~~~~~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. ~~~~~~~~~~~~~~~ !!! error TS2701: The target of an object rest assignment must be a variable or a property access. \ No newline at end of file