Fresh {} is subtype of object (#49503)

* Fresh {} is subtype of object

* Add regression test
This commit is contained in:
Anders Hejlsberg 2022-06-13 12:21:51 -07:00 committed by GitHub
parent 2ecde27187
commit dc6a80bd00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 108 additions and 2 deletions

View File

@ -18189,7 +18189,7 @@ namespace ts {
// Since unions and intersections may reduce to `never`, we exclude them here.
if (s & TypeFlags.Undefined && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & (TypeFlags.Undefined | TypeFlags.Void))) return true;
if (s & TypeFlags.Null && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & TypeFlags.Null)) return true;
if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive && !(relation === strictSubtypeRelation && isEmptyAnonymousObjectType(source))) return true;
if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive && !(relation === strictSubtypeRelation && isEmptyAnonymousObjectType(source) && !(getObjectFlags(source) & ObjectFlags.FreshLiteral))) return true;
if (relation === assignableRelation || relation === comparableRelation) {
if (s & TypeFlags.Any) return true;
// Type number or any numeric literal type is assignable to any numeric enum type or any
@ -18935,7 +18935,7 @@ namespace ts {
return typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), target as UnionType, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive));
}
if (target.flags & TypeFlags.Intersection) {
return typeRelatedToEachType(getRegularTypeOfObjectLiteral(source), target as IntersectionType, reportErrors, IntersectionState.Target);
return typeRelatedToEachType(source, target as IntersectionType, reportErrors, IntersectionState.Target);
}
// Source is an intersection. For the comparable relation, if the target is a primitive type we hoist the
// constraints of all non-primitive types in the source into a new intersection. We do this because the

View File

@ -0,0 +1,32 @@
//// [nonPrimitiveAndEmptyObject.ts]
// Repro from #49480
export interface BarProps {
barProp?: string;
}
export interface FooProps {
fooProps?: BarProps & object;
}
declare const foo: FooProps;
const { fooProps = {} } = foo;
fooProps.barProp;
//// [nonPrimitiveAndEmptyObject.js]
"use strict";
// Repro from #49480
exports.__esModule = true;
var _a = foo.fooProps, fooProps = _a === void 0 ? {} : _a;
fooProps.barProp;
//// [nonPrimitiveAndEmptyObject.d.ts]
export interface BarProps {
barProp?: string;
}
export interface FooProps {
fooProps?: BarProps & object;
}

View File

@ -0,0 +1,31 @@
=== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndEmptyObject.ts ===
// Repro from #49480
export interface BarProps {
>BarProps : Symbol(BarProps, Decl(nonPrimitiveAndEmptyObject.ts, 0, 0))
barProp?: string;
>barProp : Symbol(BarProps.barProp, Decl(nonPrimitiveAndEmptyObject.ts, 2, 27))
}
export interface FooProps {
>FooProps : Symbol(FooProps, Decl(nonPrimitiveAndEmptyObject.ts, 4, 1))
fooProps?: BarProps & object;
>fooProps : Symbol(FooProps.fooProps, Decl(nonPrimitiveAndEmptyObject.ts, 6, 27))
>BarProps : Symbol(BarProps, Decl(nonPrimitiveAndEmptyObject.ts, 0, 0))
}
declare const foo: FooProps;
>foo : Symbol(foo, Decl(nonPrimitiveAndEmptyObject.ts, 10, 13))
>FooProps : Symbol(FooProps, Decl(nonPrimitiveAndEmptyObject.ts, 4, 1))
const { fooProps = {} } = foo;
>fooProps : Symbol(fooProps, Decl(nonPrimitiveAndEmptyObject.ts, 11, 7))
>foo : Symbol(foo, Decl(nonPrimitiveAndEmptyObject.ts, 10, 13))
fooProps.barProp;
>fooProps.barProp : Symbol(BarProps.barProp, Decl(nonPrimitiveAndEmptyObject.ts, 2, 27))
>fooProps : Symbol(fooProps, Decl(nonPrimitiveAndEmptyObject.ts, 11, 7))
>barProp : Symbol(BarProps.barProp, Decl(nonPrimitiveAndEmptyObject.ts, 2, 27))

View File

@ -0,0 +1,26 @@
=== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndEmptyObject.ts ===
// Repro from #49480
export interface BarProps {
barProp?: string;
>barProp : string | undefined
}
export interface FooProps {
fooProps?: BarProps & object;
>fooProps : (BarProps & object) | undefined
}
declare const foo: FooProps;
>foo : FooProps
const { fooProps = {} } = foo;
>fooProps : BarProps & object
>{} : {}
>foo : FooProps
fooProps.barProp;
>fooProps.barProp : string | undefined
>fooProps : BarProps & object
>barProp : string | undefined

View File

@ -0,0 +1,17 @@
// @strict: true
// @declaration: true
// Repro from #49480
export interface BarProps {
barProp?: string;
}
export interface FooProps {
fooProps?: BarProps & object;
}
declare const foo: FooProps;
const { fooProps = {} } = foo;
fooProps.barProp;