From 2be814d927962dd39b9f703d25c1168cc1da5ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 8 Aug 2023 23:42:50 +0200 Subject: [PATCH] Fixed contextual types of optional properties with `exactOptionalPropertyTypes` (#55177) --- src/compiler/checker.ts | 4 +- ...actoptionalpropertytypes=false).errors.txt | 19 ++++++++ ...(exactoptionalpropertytypes=false).symbols | 36 +++++++++++++++ ...ty(exactoptionalpropertytypes=false).types | 45 +++++++++++++++++++ ...y(exactoptionalpropertytypes=true).symbols | 36 +++++++++++++++ ...rty(exactoptionalpropertytypes=true).types | 45 +++++++++++++++++++ .../contextuallyTypedOptionalProperty.ts | 13 ++++++ 7 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=false).errors.txt create mode 100644 tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=false).symbols create mode 100644 tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=false).types create mode 100644 tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=true).symbols create mode 100644 tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=true).types create mode 100644 tests/cases/compiler/contextuallyTypedOptionalProperty.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bf3081ca9b3..77afc6bf208 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29247,7 +29247,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (t.flags & TypeFlags.StructuredType) { const prop = getPropertyOfType(t, name); if (prop) { - return isCircularMappedProperty(prop) ? undefined : getTypeOfSymbol(prop); + return isCircularMappedProperty(prop) ? undefined : removeMissingType(getTypeOfSymbol(prop), !!(prop && prop.flags & SymbolFlags.Optional)); } if (isTupleType(t) && isNumericLiteralName(name) && +name >= 0) { const restType = getElementTypeOfSliceOfTupleType(t, t.target.fixedLength, /*endSkipCount*/ 0, /*writing*/ false, /*noReductions*/ true); @@ -29324,7 +29324,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If index is before any spread element and within the fixed part of the contextual tuple type, return // the type of the contextual tuple element. if ((firstSpreadIndex === undefined || index < firstSpreadIndex) && index < t.target.fixedLength) { - return getTypeArguments(t)[index]; + return removeMissingType(getTypeArguments(t)[index], !!(t.target.elementFlags[index] && ElementFlags.Optional)); } // When the length is known and the index is after all spread elements we compute the offset from the element // to the end and the number of ending fixed elements in the contextual tuple type. diff --git a/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=false).errors.txt b/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=false).errors.txt new file mode 100644 index 00000000000..12e52a606bd --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=false).errors.txt @@ -0,0 +1,19 @@ +contextuallyTypedOptionalProperty.ts(6,21): error TS18048: 'y' is possibly 'undefined'. +contextuallyTypedOptionalProperty.ts(9,18): error TS18048: 'y' is possibly 'undefined'. + + +==== contextuallyTypedOptionalProperty.ts (2 errors) ==== + // repro from https://github.com/microsoft/TypeScript/issues/55164 + + declare function match(cb: (value: T) => boolean): T; + + declare function foo(pos: { x?: number; y?: number }): boolean; + foo({ y: match(y => y > 0) }) + ~ +!!! error TS18048: 'y' is possibly 'undefined'. + + declare function foo2(point: [number?]): boolean; + foo2([match(y => y > 0)]) + ~ +!!! error TS18048: 'y' is possibly 'undefined'. + \ No newline at end of file diff --git a/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=false).symbols b/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=false).symbols new file mode 100644 index 00000000000..00a32ac486b --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=false).symbols @@ -0,0 +1,36 @@ +//// [tests/cases/compiler/contextuallyTypedOptionalProperty.ts] //// + +=== contextuallyTypedOptionalProperty.ts === +// repro from https://github.com/microsoft/TypeScript/issues/55164 + +declare function match(cb: (value: T) => boolean): T; +>match : Symbol(match, Decl(contextuallyTypedOptionalProperty.ts, 0, 0)) +>T : Symbol(T, Decl(contextuallyTypedOptionalProperty.ts, 2, 23)) +>cb : Symbol(cb, Decl(contextuallyTypedOptionalProperty.ts, 2, 26)) +>value : Symbol(value, Decl(contextuallyTypedOptionalProperty.ts, 2, 31)) +>T : Symbol(T, Decl(contextuallyTypedOptionalProperty.ts, 2, 23)) +>T : Symbol(T, Decl(contextuallyTypedOptionalProperty.ts, 2, 23)) + +declare function foo(pos: { x?: number; y?: number }): boolean; +>foo : Symbol(foo, Decl(contextuallyTypedOptionalProperty.ts, 2, 56)) +>pos : Symbol(pos, Decl(contextuallyTypedOptionalProperty.ts, 4, 21)) +>x : Symbol(x, Decl(contextuallyTypedOptionalProperty.ts, 4, 27)) +>y : Symbol(y, Decl(contextuallyTypedOptionalProperty.ts, 4, 39)) + +foo({ y: match(y => y > 0) }) +>foo : Symbol(foo, Decl(contextuallyTypedOptionalProperty.ts, 2, 56)) +>y : Symbol(y, Decl(contextuallyTypedOptionalProperty.ts, 5, 5)) +>match : Symbol(match, Decl(contextuallyTypedOptionalProperty.ts, 0, 0)) +>y : Symbol(y, Decl(contextuallyTypedOptionalProperty.ts, 5, 15)) +>y : Symbol(y, Decl(contextuallyTypedOptionalProperty.ts, 5, 15)) + +declare function foo2(point: [number?]): boolean; +>foo2 : Symbol(foo2, Decl(contextuallyTypedOptionalProperty.ts, 5, 29)) +>point : Symbol(point, Decl(contextuallyTypedOptionalProperty.ts, 7, 22)) + +foo2([match(y => y > 0)]) +>foo2 : Symbol(foo2, Decl(contextuallyTypedOptionalProperty.ts, 5, 29)) +>match : Symbol(match, Decl(contextuallyTypedOptionalProperty.ts, 0, 0)) +>y : Symbol(y, Decl(contextuallyTypedOptionalProperty.ts, 8, 12)) +>y : Symbol(y, Decl(contextuallyTypedOptionalProperty.ts, 8, 12)) + diff --git a/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=false).types b/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=false).types new file mode 100644 index 00000000000..f54c0619434 --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=false).types @@ -0,0 +1,45 @@ +//// [tests/cases/compiler/contextuallyTypedOptionalProperty.ts] //// + +=== contextuallyTypedOptionalProperty.ts === +// repro from https://github.com/microsoft/TypeScript/issues/55164 + +declare function match(cb: (value: T) => boolean): T; +>match : (cb: (value: T) => boolean) => T +>cb : (value: T) => boolean +>value : T + +declare function foo(pos: { x?: number; y?: number }): boolean; +>foo : (pos: { x?: number; y?: number;}) => boolean +>pos : { x?: number | undefined; y?: number | undefined; } +>x : number | undefined +>y : number | undefined + +foo({ y: match(y => y > 0) }) +>foo({ y: match(y => y > 0) }) : boolean +>foo : (pos: { x?: number | undefined; y?: number | undefined; }) => boolean +>{ y: match(y => y > 0) } : { y: number | undefined; } +>y : number | undefined +>match(y => y > 0) : number | undefined +>match : (cb: (value: T) => boolean) => T +>y => y > 0 : (y: number | undefined) => boolean +>y : number | undefined +>y > 0 : boolean +>y : number | undefined +>0 : 0 + +declare function foo2(point: [number?]): boolean; +>foo2 : (point: [number?]) => boolean +>point : [(number | undefined)?] + +foo2([match(y => y > 0)]) +>foo2([match(y => y > 0)]) : boolean +>foo2 : (point: [(number | undefined)?]) => boolean +>[match(y => y > 0)] : [number | undefined] +>match(y => y > 0) : number | undefined +>match : (cb: (value: T) => boolean) => T +>y => y > 0 : (y: number | undefined) => boolean +>y : number | undefined +>y > 0 : boolean +>y : number | undefined +>0 : 0 + diff --git a/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=true).symbols b/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=true).symbols new file mode 100644 index 00000000000..00a32ac486b --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=true).symbols @@ -0,0 +1,36 @@ +//// [tests/cases/compiler/contextuallyTypedOptionalProperty.ts] //// + +=== contextuallyTypedOptionalProperty.ts === +// repro from https://github.com/microsoft/TypeScript/issues/55164 + +declare function match(cb: (value: T) => boolean): T; +>match : Symbol(match, Decl(contextuallyTypedOptionalProperty.ts, 0, 0)) +>T : Symbol(T, Decl(contextuallyTypedOptionalProperty.ts, 2, 23)) +>cb : Symbol(cb, Decl(contextuallyTypedOptionalProperty.ts, 2, 26)) +>value : Symbol(value, Decl(contextuallyTypedOptionalProperty.ts, 2, 31)) +>T : Symbol(T, Decl(contextuallyTypedOptionalProperty.ts, 2, 23)) +>T : Symbol(T, Decl(contextuallyTypedOptionalProperty.ts, 2, 23)) + +declare function foo(pos: { x?: number; y?: number }): boolean; +>foo : Symbol(foo, Decl(contextuallyTypedOptionalProperty.ts, 2, 56)) +>pos : Symbol(pos, Decl(contextuallyTypedOptionalProperty.ts, 4, 21)) +>x : Symbol(x, Decl(contextuallyTypedOptionalProperty.ts, 4, 27)) +>y : Symbol(y, Decl(contextuallyTypedOptionalProperty.ts, 4, 39)) + +foo({ y: match(y => y > 0) }) +>foo : Symbol(foo, Decl(contextuallyTypedOptionalProperty.ts, 2, 56)) +>y : Symbol(y, Decl(contextuallyTypedOptionalProperty.ts, 5, 5)) +>match : Symbol(match, Decl(contextuallyTypedOptionalProperty.ts, 0, 0)) +>y : Symbol(y, Decl(contextuallyTypedOptionalProperty.ts, 5, 15)) +>y : Symbol(y, Decl(contextuallyTypedOptionalProperty.ts, 5, 15)) + +declare function foo2(point: [number?]): boolean; +>foo2 : Symbol(foo2, Decl(contextuallyTypedOptionalProperty.ts, 5, 29)) +>point : Symbol(point, Decl(contextuallyTypedOptionalProperty.ts, 7, 22)) + +foo2([match(y => y > 0)]) +>foo2 : Symbol(foo2, Decl(contextuallyTypedOptionalProperty.ts, 5, 29)) +>match : Symbol(match, Decl(contextuallyTypedOptionalProperty.ts, 0, 0)) +>y : Symbol(y, Decl(contextuallyTypedOptionalProperty.ts, 8, 12)) +>y : Symbol(y, Decl(contextuallyTypedOptionalProperty.ts, 8, 12)) + diff --git a/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=true).types b/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=true).types new file mode 100644 index 00000000000..df0a98863d7 --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedOptionalProperty(exactoptionalpropertytypes=true).types @@ -0,0 +1,45 @@ +//// [tests/cases/compiler/contextuallyTypedOptionalProperty.ts] //// + +=== contextuallyTypedOptionalProperty.ts === +// repro from https://github.com/microsoft/TypeScript/issues/55164 + +declare function match(cb: (value: T) => boolean): T; +>match : (cb: (value: T) => boolean) => T +>cb : (value: T) => boolean +>value : T + +declare function foo(pos: { x?: number; y?: number }): boolean; +>foo : (pos: { x?: number; y?: number;}) => boolean +>pos : { x?: number; y?: number; } +>x : number | undefined +>y : number | undefined + +foo({ y: match(y => y > 0) }) +>foo({ y: match(y => y > 0) }) : boolean +>foo : (pos: { x?: number; y?: number; }) => boolean +>{ y: match(y => y > 0) } : { y: number; } +>y : number +>match(y => y > 0) : number +>match : (cb: (value: T) => boolean) => T +>y => y > 0 : (y: number) => boolean +>y : number +>y > 0 : boolean +>y : number +>0 : 0 + +declare function foo2(point: [number?]): boolean; +>foo2 : (point: [number?]) => boolean +>point : [number?] + +foo2([match(y => y > 0)]) +>foo2([match(y => y > 0)]) : boolean +>foo2 : (point: [number?]) => boolean +>[match(y => y > 0)] : [number] +>match(y => y > 0) : number +>match : (cb: (value: T) => boolean) => T +>y => y > 0 : (y: number) => boolean +>y : number +>y > 0 : boolean +>y : number +>0 : 0 + diff --git a/tests/cases/compiler/contextuallyTypedOptionalProperty.ts b/tests/cases/compiler/contextuallyTypedOptionalProperty.ts new file mode 100644 index 00000000000..9587ab27a5b --- /dev/null +++ b/tests/cases/compiler/contextuallyTypedOptionalProperty.ts @@ -0,0 +1,13 @@ +// @strict: true +// @exactOptionalPropertyTypes: true, false +// @noEmit: true + +// repro from https://github.com/microsoft/TypeScript/issues/55164 + +declare function match(cb: (value: T) => boolean): T; + +declare function foo(pos: { x?: number; y?: number }): boolean; +foo({ y: match(y => y > 0) }) + +declare function foo2(point: [number?]): boolean; +foo2([match(y => y > 0)])