diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1506c4809ef33..1ffce28298667 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,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'. - 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; + } + + // 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 = + 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'. + (getBaseConstraintOfType(type) || unknownType) === unknownType && isEmptyObjectType(contextualType); + + return substituteConstraints ? getTypeWithConstraintsSubstituted() : type; + + function getTypeWithConstraintsSubstituted() { + return mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t); + } } function isExportOrExportExpression(location: Node) { 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/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).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..86668ece67517 --- /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 : object +>length : number +>keysOfEmptyObject(b).length : number +>keysOfEmptyObject(b) : string[] +>keysOfEmptyObject : (o: {}) => string[] +>b : object +>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 : object +>length : number +>keysOfNonPrimitive(b).length : number +>keysOfNonPrimitive(b) : string[] +>keysOfNonPrimitive : (o: object) => string[] +>b : object +>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 : object +>length : number +>keysOfEmptyObject(b).length : number +>keysOfEmptyObject(b) : string[] +>keysOfEmptyObject : (o: {}) => string[] +>b : object +>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 : object +>length : number +>keysOfNonPrimitive(b).length : number +>keysOfNonPrimitive(b) : string[] +>keysOfNonPrimitive : (o: object) => string[] +>b : object +>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).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..86668ece67517 --- /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 : object +>length : number +>keysOfEmptyObject(b).length : number +>keysOfEmptyObject(b) : string[] +>keysOfEmptyObject : (o: {}) => string[] +>b : object +>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 : object +>length : number +>keysOfNonPrimitive(b).length : number +>keysOfNonPrimitive(b) : string[] +>keysOfNonPrimitive : (o: object) => string[] +>b : object +>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 : object +>length : number +>keysOfEmptyObject(b).length : number +>keysOfEmptyObject(b) : string[] +>keysOfEmptyObject : (o: {}) => string[] +>b : object +>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 : object +>length : number +>keysOfNonPrimitive(b).length : number +>keysOfNonPrimitive(b) : string[] +>keysOfNonPrimitive : (o: object) => string[] +>b : object +>length : number + + return [a, b]; +>[a, b] : [T, T] +>a : T +>b : T + } + return undefined; +>undefined : undefined + } +} + 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..ad8e5a3def0c5 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; } 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..3a25010d82668 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 : {} 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 } 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; + } +}