diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b439b7fd9c579..4f7618dccfe59 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22340,11 +22340,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getTypeOfPropertyInTypes(types: Type[], name: __String) { + function getTypeOfPropertyInTargetTypes(types: Type[], name: __String) { const appendPropType = (propTypes: Type[] | undefined, type: Type) => { type = getApparentType(type); const prop = type.flags & TypeFlags.UnionOrIntersection ? getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name) : getPropertyOfObjectType(type, name); - const propType = prop && getTypeOfSymbol(prop) || getApplicableIndexInfoForName(type, name)?.type || undefinedType; + const propType = prop && getNonMissingTypeOfSymbol(prop) || getApplicableIndexInfoForName(type, name)?.type || undefinedType; return append(propTypes, propType); }; return getUnionType(reduceLeft(types, appendPropType, /*initial*/ undefined) || emptyArray); @@ -22421,7 +22421,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return true; } - if (checkTypes && !isRelatedTo(getTypeOfSymbol(prop), getTypeOfPropertyInTypes(checkTypes, prop.escapedName), RecursionFlags.Both, reportErrors)) { + if (checkTypes && !isRelatedTo(getTypeOfSymbol(prop), getTypeOfPropertyInTargetTypes(checkTypes, prop.escapedName), RecursionFlags.Both, reportErrors)) { if (reportErrors) { reportIncompatibleError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(prop)); } @@ -23646,8 +23646,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isPropertySymbolTypeRelated(sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { - const targetIsOptional = strictNullChecks && !!(getCheckFlags(targetProp) & CheckFlags.Partial); - const effectiveTarget = addOptionality(getNonMissingTypeOfSymbol(targetProp), /*isProperty*/ false, targetIsOptional); + const effectiveTarget = getNonMissingTypeOfSymbol(targetProp); const effectiveSource = getTypeOfSourceProperty(sourceProp); return isRelatedTo(effectiveSource, effectiveTarget, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); } diff --git a/tests/baselines/reference/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.errors.txt b/tests/baselines/reference/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.errors.txt new file mode 100644 index 0000000000000..246d8e7d7335b --- /dev/null +++ b/tests/baselines/reference/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.errors.txt @@ -0,0 +1,59 @@ +incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts(5,3): error TS2322: Type 'number' is not assignable to type 'never'. +incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts(10,7): error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'T2'. + Types of property 'b' are incompatible. + Type 'number' is not assignable to type 'never'. +incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts(21,7): error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'T1'. + Types of property 'b' are incompatible. + Type 'number' is not assignable to type 'never'. +incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts(28,7): error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'T2'. + Type '{ a: number; b: number; }' is not assignable to type '{ a: number; b?: never; }'. + Types of property 'b' are incompatible. + Type 'number' is not assignable to type 'never'. + + +==== incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts (4 errors) ==== + type T1 = { a: number; b?: never }; + + const t1: T1 = { + a: 0, + b: 0, + ~ +!!! error TS2322: Type 'number' is not assignable to type 'never'. +!!! related TS6500 incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts:1:24: The expected type comes from property 'b' which is declared here on type 'T1' + }; + + type T2 = { a: number; b?: never } | { a?: never; b: number }; + + const t2: T2 = { + ~~ +!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'T2'. +!!! error TS2322: Types of property 'b' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'never'. + a: 0, + b: 0, + }; + + // for comparison with the above: + const obj1 = { + a: 0, + b: 0, + } + + const t3: T1 = obj1; + ~~ +!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'T1'. +!!! error TS2322: Types of property 'b' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'never'. + + const obj2 = { + a: 0, + b: 0, + }; + + const t4: T2 = obj2; + ~~ +!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'T2'. +!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type '{ a: number; b?: never; }'. +!!! error TS2322: Types of property 'b' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'never'. + \ No newline at end of file diff --git a/tests/baselines/reference/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.symbols b/tests/baselines/reference/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.symbols new file mode 100644 index 0000000000000..ebff86c9b8d9a --- /dev/null +++ b/tests/baselines/reference/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.symbols @@ -0,0 +1,71 @@ +//// [tests/cases/compiler/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts] //// + +=== incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts === +type T1 = { a: number; b?: never }; +>T1 : Symbol(T1, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 0, 0)) +>a : Symbol(a, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 0, 11)) +>b : Symbol(b, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 0, 22)) + +const t1: T1 = { +>t1 : Symbol(t1, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 2, 5)) +>T1 : Symbol(T1, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 0, 0)) + + a: 0, +>a : Symbol(a, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 2, 16)) + + b: 0, +>b : Symbol(b, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 3, 7)) + +}; + +type T2 = { a: number; b?: never } | { a?: never; b: number }; +>T2 : Symbol(T2, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 5, 2)) +>a : Symbol(a, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 7, 11)) +>b : Symbol(b, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 7, 22)) +>a : Symbol(a, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 7, 38)) +>b : Symbol(b, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 7, 49)) + +const t2: T2 = { +>t2 : Symbol(t2, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 9, 5)) +>T2 : Symbol(T2, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 5, 2)) + + a: 0, +>a : Symbol(a, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 9, 16)) + + b: 0, +>b : Symbol(b, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 10, 7)) + +}; + +// for comparison with the above: +const obj1 = { +>obj1 : Symbol(obj1, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 15, 5)) + + a: 0, +>a : Symbol(a, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 15, 14)) + + b: 0, +>b : Symbol(b, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 16, 7)) +} + +const t3: T1 = obj1; +>t3 : Symbol(t3, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 20, 5)) +>T1 : Symbol(T1, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 0, 0)) +>obj1 : Symbol(obj1, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 15, 5)) + +const obj2 = { +>obj2 : Symbol(obj2, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 22, 5)) + + a: 0, +>a : Symbol(a, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 22, 14)) + + b: 0, +>b : Symbol(b, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 23, 7)) + +}; + +const t4: T2 = obj2; +>t4 : Symbol(t4, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 27, 5)) +>T2 : Symbol(T2, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 5, 2)) +>obj2 : Symbol(obj2, Decl(incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts, 22, 5)) + diff --git a/tests/baselines/reference/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.types b/tests/baselines/reference/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.types new file mode 100644 index 0000000000000..f8b187f4fff7e --- /dev/null +++ b/tests/baselines/reference/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.types @@ -0,0 +1,115 @@ +//// [tests/cases/compiler/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts] //// + +=== incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts === +type T1 = { a: number; b?: never }; +>T1 : T1 +> : ^^ +>a : number +> : ^^^^^^ +>b : undefined +> : ^^^^^^^^^ + +const t1: T1 = { +>t1 : T1 +> : ^^ +>{ a: 0, b: 0,} : { a: number; b: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + a: 0, +>a : number +> : ^^^^^^ +>0 : 0 +> : ^ + + b: 0, +>b : number +> : ^^^^^^ +>0 : 0 +> : ^ + +}; + +type T2 = { a: number; b?: never } | { a?: never; b: number }; +>T2 : T2 +> : ^^ +>a : number +> : ^^^^^^ +>b : undefined +> : ^^^^^^^^^ +>a : undefined +> : ^^^^^^^^^ +>b : number +> : ^^^^^^ + +const t2: T2 = { +>t2 : T2 +> : ^^ +>{ a: 0, b: 0,} : { a: number; b: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + a: 0, +>a : number +> : ^^^^^^ +>0 : 0 +> : ^ + + b: 0, +>b : number +> : ^^^^^^ +>0 : 0 +> : ^ + +}; + +// for comparison with the above: +const obj1 = { +>obj1 : { a: number; b: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ a: 0, b: 0,} : { a: number; b: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + a: 0, +>a : number +> : ^^^^^^ +>0 : 0 +> : ^ + + b: 0, +>b : number +> : ^^^^^^ +>0 : 0 +> : ^ +} + +const t3: T1 = obj1; +>t3 : T1 +> : ^^ +>obj1 : { a: number; b: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + +const obj2 = { +>obj2 : { a: number; b: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ a: 0, b: 0,} : { a: number; b: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + + a: 0, +>a : number +> : ^^^^^^ +>0 : 0 +> : ^ + + b: 0, +>b : number +> : ^^^^^^ +>0 : 0 +> : ^ + +}; + +const t4: T2 = obj2; +>t4 : T2 +> : ^^ +>obj2 : { a: number; b: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/cases/compiler/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts b/tests/cases/compiler/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts new file mode 100644 index 0000000000000..9d8d5b0255a1f --- /dev/null +++ b/tests/cases/compiler/incompatiblePropertyErrorObjLiteralExactOptionalPropertyTypes1.ts @@ -0,0 +1,32 @@ +// @strict: true +// @noEmit: true +// @exactOptionalPropertyTypes: true + +type T1 = { a: number; b?: never }; + +const t1: T1 = { + a: 0, + b: 0, +}; + +type T2 = { a: number; b?: never } | { a?: never; b: number }; + +const t2: T2 = { + a: 0, + b: 0, +}; + +// for comparison with the above: +const obj1 = { + a: 0, + b: 0, +} + +const t3: T1 = obj1; + +const obj2 = { + a: 0, + b: 0, +}; + +const t4: T2 = obj2;