From 1f43c8d1baa88d7cb9a67326971c2656efc006b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 20 Jun 2023 22:28:02 +0200 Subject: [PATCH 1/6] Remove missing type from tuple type arguments under `exactOptionalPropertyTypes` --- src/compiler/checker.ts | 2 +- ...propertytypes=false,target=es5).errors.txt | 20 ++++++++++++ ...nalpropertytypes=false,target=es5).symbols | 31 +++++++++++++++++++ ...ionalpropertytypes=false,target=es5).types | 29 +++++++++++++++++ ...pertytypes=false,target=esnext).errors.txt | 20 ++++++++++++ ...propertytypes=false,target=esnext).symbols | 31 +++++++++++++++++++ ...alpropertytypes=false,target=esnext).types | 29 +++++++++++++++++ ...onalpropertytypes=true,target=es5).symbols | 31 +++++++++++++++++++ ...tionalpropertytypes=true,target=es5).types | 29 +++++++++++++++++ ...lpropertytypes=true,target=esnext).symbols | 31 +++++++++++++++++++ ...nalpropertytypes=true,target=esnext).types | 29 +++++++++++++++++ .../compiler/forOfOptionalTupleMember.ts | 18 +++++++++++ 12 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).errors.txt create mode 100644 tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).symbols create mode 100644 tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).types create mode 100644 tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).errors.txt create mode 100644 tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).symbols create mode 100644 tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).types create mode 100644 tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).symbols create mode 100644 tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).types create mode 100644 tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).symbols create mode 100644 tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).types create mode 100644 tests/cases/compiler/forOfOptionalTupleMember.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4eb2db0bd29e8..28ac3e2a052d9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15217,7 +15217,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeArguments = !node ? emptyArray : node.kind === SyntaxKind.TypeReference ? concatenate(type.target.outerTypeParameters, getEffectiveTypeArguments(node, type.target.localTypeParameters!)) : node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : - map(node.elements, getTypeFromTypeNode); + map(node.elements, element => removeMissingType(getTypeFromTypeNode(element), element.kind === SyntaxKind.OptionalType)); if (popTypeResolution()) { type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments; } diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).errors.txt b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).errors.txt new file mode 100644 index 0000000000000..166d2bed58d39 --- /dev/null +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).errors.txt @@ -0,0 +1,20 @@ +forOfOptionalTupleMember.ts(12,3): error TS18048: 'item' is possibly 'undefined'. + + +==== forOfOptionalTupleMember.ts (1 errors) ==== + // repro from https://github.com/microsoft/TypeScript/issues/54302 + + type Item = { + value: string; + }; + + type Foo = [Item?]; + + declare const foo: Foo; + + for (let item of foo) { + item.value; + ~~~~ +!!! error TS18048: 'item' is possibly 'undefined'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).symbols b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).symbols new file mode 100644 index 0000000000000..32d94a8c8f21e --- /dev/null +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).symbols @@ -0,0 +1,31 @@ +//// [tests/cases/compiler/forOfOptionalTupleMember.ts] //// + +=== forOfOptionalTupleMember.ts === +// repro from https://github.com/microsoft/TypeScript/issues/54302 + +type Item = { +>Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) + + value: string; +>value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) + +}; + +type Foo = [Item?]; +>Foo : Symbol(Foo, Decl(forOfOptionalTupleMember.ts, 4, 2)) +>Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) + +declare const foo: Foo; +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) +>Foo : Symbol(Foo, Decl(forOfOptionalTupleMember.ts, 4, 2)) + +for (let item of foo) { +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) + + item.value; +>item.value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) +>value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).types b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).types new file mode 100644 index 0000000000000..ddfd8cbdfb05c --- /dev/null +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).types @@ -0,0 +1,29 @@ +//// [tests/cases/compiler/forOfOptionalTupleMember.ts] //// + +=== forOfOptionalTupleMember.ts === +// repro from https://github.com/microsoft/TypeScript/issues/54302 + +type Item = { +>Item : { value: string; } + + value: string; +>value : string + +}; + +type Foo = [Item?]; +>Foo : [(Item | undefined)?] + +declare const foo: Foo; +>foo : Foo + +for (let item of foo) { +>item : Item | undefined +>foo : Foo + + item.value; +>item.value : string +>item : Item | undefined +>value : string +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).errors.txt b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).errors.txt new file mode 100644 index 0000000000000..166d2bed58d39 --- /dev/null +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).errors.txt @@ -0,0 +1,20 @@ +forOfOptionalTupleMember.ts(12,3): error TS18048: 'item' is possibly 'undefined'. + + +==== forOfOptionalTupleMember.ts (1 errors) ==== + // repro from https://github.com/microsoft/TypeScript/issues/54302 + + type Item = { + value: string; + }; + + type Foo = [Item?]; + + declare const foo: Foo; + + for (let item of foo) { + item.value; + ~~~~ +!!! error TS18048: 'item' is possibly 'undefined'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).symbols b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).symbols new file mode 100644 index 0000000000000..32d94a8c8f21e --- /dev/null +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).symbols @@ -0,0 +1,31 @@ +//// [tests/cases/compiler/forOfOptionalTupleMember.ts] //// + +=== forOfOptionalTupleMember.ts === +// repro from https://github.com/microsoft/TypeScript/issues/54302 + +type Item = { +>Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) + + value: string; +>value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) + +}; + +type Foo = [Item?]; +>Foo : Symbol(Foo, Decl(forOfOptionalTupleMember.ts, 4, 2)) +>Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) + +declare const foo: Foo; +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) +>Foo : Symbol(Foo, Decl(forOfOptionalTupleMember.ts, 4, 2)) + +for (let item of foo) { +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) + + item.value; +>item.value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) +>value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).types b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).types new file mode 100644 index 0000000000000..ddfd8cbdfb05c --- /dev/null +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).types @@ -0,0 +1,29 @@ +//// [tests/cases/compiler/forOfOptionalTupleMember.ts] //// + +=== forOfOptionalTupleMember.ts === +// repro from https://github.com/microsoft/TypeScript/issues/54302 + +type Item = { +>Item : { value: string; } + + value: string; +>value : string + +}; + +type Foo = [Item?]; +>Foo : [(Item | undefined)?] + +declare const foo: Foo; +>foo : Foo + +for (let item of foo) { +>item : Item | undefined +>foo : Foo + + item.value; +>item.value : string +>item : Item | undefined +>value : string +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).symbols b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).symbols new file mode 100644 index 0000000000000..32d94a8c8f21e --- /dev/null +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).symbols @@ -0,0 +1,31 @@ +//// [tests/cases/compiler/forOfOptionalTupleMember.ts] //// + +=== forOfOptionalTupleMember.ts === +// repro from https://github.com/microsoft/TypeScript/issues/54302 + +type Item = { +>Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) + + value: string; +>value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) + +}; + +type Foo = [Item?]; +>Foo : Symbol(Foo, Decl(forOfOptionalTupleMember.ts, 4, 2)) +>Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) + +declare const foo: Foo; +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) +>Foo : Symbol(Foo, Decl(forOfOptionalTupleMember.ts, 4, 2)) + +for (let item of foo) { +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) + + item.value; +>item.value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) +>value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).types b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).types new file mode 100644 index 0000000000000..7e7574e33081c --- /dev/null +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).types @@ -0,0 +1,29 @@ +//// [tests/cases/compiler/forOfOptionalTupleMember.ts] //// + +=== forOfOptionalTupleMember.ts === +// repro from https://github.com/microsoft/TypeScript/issues/54302 + +type Item = { +>Item : { value: string; } + + value: string; +>value : string + +}; + +type Foo = [Item?]; +>Foo : [Item?] + +declare const foo: Foo; +>foo : Foo + +for (let item of foo) { +>item : Item +>foo : Foo + + item.value; +>item.value : string +>item : Item +>value : string +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).symbols b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).symbols new file mode 100644 index 0000000000000..32d94a8c8f21e --- /dev/null +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).symbols @@ -0,0 +1,31 @@ +//// [tests/cases/compiler/forOfOptionalTupleMember.ts] //// + +=== forOfOptionalTupleMember.ts === +// repro from https://github.com/microsoft/TypeScript/issues/54302 + +type Item = { +>Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) + + value: string; +>value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) + +}; + +type Foo = [Item?]; +>Foo : Symbol(Foo, Decl(forOfOptionalTupleMember.ts, 4, 2)) +>Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) + +declare const foo: Foo; +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) +>Foo : Symbol(Foo, Decl(forOfOptionalTupleMember.ts, 4, 2)) + +for (let item of foo) { +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) + + item.value; +>item.value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) +>value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).types b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).types new file mode 100644 index 0000000000000..7e7574e33081c --- /dev/null +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).types @@ -0,0 +1,29 @@ +//// [tests/cases/compiler/forOfOptionalTupleMember.ts] //// + +=== forOfOptionalTupleMember.ts === +// repro from https://github.com/microsoft/TypeScript/issues/54302 + +type Item = { +>Item : { value: string; } + + value: string; +>value : string + +}; + +type Foo = [Item?]; +>Foo : [Item?] + +declare const foo: Foo; +>foo : Foo + +for (let item of foo) { +>item : Item +>foo : Foo + + item.value; +>item.value : string +>item : Item +>value : string +} + diff --git a/tests/cases/compiler/forOfOptionalTupleMember.ts b/tests/cases/compiler/forOfOptionalTupleMember.ts new file mode 100644 index 0000000000000..3f5525124938b --- /dev/null +++ b/tests/cases/compiler/forOfOptionalTupleMember.ts @@ -0,0 +1,18 @@ +// @strict: true +// @target: es5, esnext +// @exactOptionalPropertyTypes: true, false +// @noEmit: true + +// repro from https://github.com/microsoft/TypeScript/issues/54302 + +type Item = { + value: string; +}; + +type Foo = [Item?]; + +declare const foo: Foo; + +for (let item of foo) { + item.value; +} From cd8f59c53e9496e2e345e5234f173f990ec0fbc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 1 Sep 2023 00:19:59 +0200 Subject: [PATCH 2/6] avoid adding a missing type instead of removing it afterward --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 512e191cce019..874318fb3bed2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15563,7 +15563,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeArguments = !node ? emptyArray : node.kind === SyntaxKind.TypeReference ? concatenate(type.target.outerTypeParameters, getEffectiveTypeArguments(node, type.target.localTypeParameters!)) : node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : - map(node.elements, element => removeMissingType(getTypeFromTypeNode(element), element.kind === SyntaxKind.OptionalType)); + map(node.elements, element => getTypeFromTypeNode(element.kind === SyntaxKind.OptionalType && exactOptionalPropertyTypes ? (element as OptionalTypeNode).type : element)); if (popTypeResolution()) { type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments; } From 31d5bf7c33bfc47c47039f277c9145dd27d35039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 1 Sep 2023 23:58:03 +0200 Subject: [PATCH 3/6] Fixed more cases --- src/compiler/checker.ts | 33 ++++++++--- ...propertytypes=false,target=es5).errors.txt | 33 +++++++++-- ...nalpropertytypes=false,target=es5).symbols | 56 +++++++++++++++++-- ...ionalpropertytypes=false,target=es5).types | 48 ++++++++++++++++ ...pertytypes=false,target=esnext).errors.txt | 33 +++++++++-- ...propertytypes=false,target=esnext).symbols | 56 +++++++++++++++++-- ...alpropertytypes=false,target=esnext).types | 48 ++++++++++++++++ ...onalpropertytypes=true,target=es5).symbols | 56 +++++++++++++++++-- ...tionalpropertytypes=true,target=es5).types | 48 ++++++++++++++++ ...lpropertytypes=true,target=esnext).symbols | 56 +++++++++++++++++-- ...nalpropertytypes=true,target=esnext).types | 48 ++++++++++++++++ .../strictOptionalProperties1.errors.txt | 16 +++++- .../compiler/forOfOptionalTupleMember.ts | 20 ++++++- 13 files changed, 515 insertions(+), 36 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 874318fb3bed2..c2d025013790f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12863,7 +12863,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { mapper = createTypeMapper(typeParameters, typeArguments); - members = createInstantiatedSymbolTable(source.declaredProperties, mapper, /*mappingThisOnly*/ typeParameters.length === 1); + const propertiesMapper = isTupleType(type) + ? createTypeMapper(typeParameters, sameMap(typeArguments, (t, i) => addOptionality(t, /*isProperty*/ true, !!(type.target.elementFlags[i] & ElementFlags.Optional)))) + : mapper; + members = createInstantiatedSymbolTable(source.declaredProperties, propertiesMapper, /*mappingThisOnly*/ typeParameters.length === 1); callSignatures = instantiateSignatures(source.declaredCallSignatures, mapper); constructSignatures = instantiateSignatures(source.declaredConstructSignatures, mapper); indexInfos = instantiateIndexInfos(source.declaredIndexInfos, mapper); @@ -15563,7 +15566,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeArguments = !node ? emptyArray : node.kind === SyntaxKind.TypeReference ? concatenate(type.target.outerTypeParameters, getEffectiveTypeArguments(node, type.target.localTypeParameters!)) : node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : - map(node.elements, element => getTypeFromTypeNode(element.kind === SyntaxKind.OptionalType && exactOptionalPropertyTypes ? (element as OptionalTypeNode).type : element)); + map(node.elements, getTypeFromTypeNode); if (popTypeResolution()) { type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments; } @@ -16552,7 +16555,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (flags & (ElementFlags.Optional | ElementFlags.Rest)) { lastOptionalOrRestIndex = expandedFlags.length; } - expandedTypes.push(flags & ElementFlags.Optional ? addOptionality(type, /*isProperty*/ true) : type); + expandedTypes.push(flags & ElementFlags.Optional && !exactOptionalPropertyTypes ? addOptionality(type, /*isProperty*/ true) : type); expandedFlags.push(flags); expandedDeclarations.push(declaration); } @@ -16591,7 +16594,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeFromOptionalTypeNode(node: OptionalTypeNode): Type { - return addOptionality(getTypeFromTypeNode(node.type), /*isProperty*/ true); + const type = getTypeFromTypeNode(node.type); + return exactOptionalPropertyTypes ? type : addOptionality(type, /*isProperty*/ true); } function getTypeId(type: Type): TypeId { @@ -18829,8 +18833,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeFromNamedTupleTypeNode(node: NamedTupleMember): Type { const links = getNodeLinks(node); - return links.resolvedType || (links.resolvedType = node.dotDotDotToken ? getTypeFromRestTypeNode(node) : - addOptionality(getTypeFromTypeNode(node.type), /*isProperty*/ true, !!node.questionToken)); + if (links.resolvedType) { + return links.resolvedType; + } + let type: Type; + if (node.dotDotDotToken) { + type = getTypeFromRestTypeNode(node); + } + else { + type = getTypeFromTypeNode(node.type); + if (!exactOptionalPropertyTypes) { + type = addOptionality(type, /*isProperty*/ true, !!node.questionToken); + } + } + return links.resolvedType = type; } function getTypeFromTypeNode(node: TypeNode): Type { @@ -22723,11 +22739,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - const sourceType = removeMissingType(sourceTypeArguments[sourcePosition], !!(sourceFlags & targetFlags & ElementFlags.Optional)); + const sourceType = sourceTypeArguments[sourcePosition]; const targetType = targetTypeArguments[targetPosition]; + const targetCheckType = sourceFlags & ElementFlags.Variadic && targetFlags & ElementFlags.Rest ? createArrayType(targetType) : targetType; - const targetCheckType = sourceFlags & ElementFlags.Variadic && targetFlags & ElementFlags.Rest ? createArrayType(targetType) : - removeMissingType(targetType, !!(targetFlags & ElementFlags.Optional)); const related = isRelatedTo(sourceType, targetCheckType, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); if (!related) { if (reportErrors && (targetArity > 1 || sourceArity > 1)) { diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).errors.txt b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).errors.txt index 166d2bed58d39..0bd718f342d0f 100644 --- a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).errors.txt +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).errors.txt @@ -1,7 +1,10 @@ -forOfOptionalTupleMember.ts(12,3): error TS18048: 'item' is possibly 'undefined'. +forOfOptionalTupleMember.ts(10,3): error TS18048: 'item' is possibly 'undefined'. +forOfOptionalTupleMember.ts(16,3): error TS18048: 'item' is possibly 'undefined'. +forOfOptionalTupleMember.ts(21,5): error TS18048: 'num' is possibly 'undefined'. +forOfOptionalTupleMember.ts(27,5): error TS18048: 'num' is possibly 'undefined'. -==== forOfOptionalTupleMember.ts (1 errors) ==== +==== forOfOptionalTupleMember.ts (4 errors) ==== // repro from https://github.com/microsoft/TypeScript/issues/54302 type Item = { @@ -9,12 +12,34 @@ forOfOptionalTupleMember.ts(12,3): error TS18048: 'item' is possibly 'undefined' }; type Foo = [Item?]; - declare const foo: Foo; - for (let item of foo) { item.value; ~~~~ !!! error TS18048: 'item' is possibly 'undefined'. } + + type Foo2 = [item?: Item]; + declare const foo2: Foo2; + for (let item of foo2) { + item.value; + ~~~~ +!!! error TS18048: 'item' is possibly 'undefined'. + } + + function fn1(t: [number, number?, number?]) { + for (let num of t) { + num.toString() + ~~~ +!!! error TS18048: 'num' is possibly 'undefined'. + } + } + + function fn2(t: [a: number, b?: number, c?: number]) { + for (let num of t) { + num.toString() + ~~~ +!!! error TS18048: 'num' is possibly 'undefined'. + } + } \ No newline at end of file diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).symbols b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).symbols index 32d94a8c8f21e..9c9a3b4bb277a 100644 --- a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).symbols +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).symbols @@ -16,16 +16,64 @@ type Foo = [Item?]; >Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) declare const foo: Foo; ->foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 7, 13)) >Foo : Symbol(Foo, Decl(forOfOptionalTupleMember.ts, 4, 2)) for (let item of foo) { ->item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) ->foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 8, 8)) +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 7, 13)) item.value; >item.value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) ->item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 8, 8)) >value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) } +type Foo2 = [item?: Item]; +>Foo2 : Symbol(Foo2, Decl(forOfOptionalTupleMember.ts, 10, 1)) +>Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) + +declare const foo2: Foo2; +>foo2 : Symbol(foo2, Decl(forOfOptionalTupleMember.ts, 13, 13)) +>Foo2 : Symbol(Foo2, Decl(forOfOptionalTupleMember.ts, 10, 1)) + +for (let item of foo2) { +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 14, 8)) +>foo2 : Symbol(foo2, Decl(forOfOptionalTupleMember.ts, 13, 13)) + + item.value; +>item.value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 14, 8)) +>value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +} + +function fn1(t: [number, number?, number?]) { +>fn1 : Symbol(fn1, Decl(forOfOptionalTupleMember.ts, 16, 1)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 18, 13)) + + for (let num of t) { +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 19, 10)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 18, 13)) + + num.toString() +>num.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 19, 10)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + } +} + +function fn2(t: [a: number, b?: number, c?: number]) { +>fn2 : Symbol(fn2, Decl(forOfOptionalTupleMember.ts, 22, 1)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 24, 13)) + + for (let num of t) { +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 25, 10)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 24, 13)) + + num.toString() +>num.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 25, 10)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + } +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).types b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).types index ddfd8cbdfb05c..9d785a30ae155 100644 --- a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).types +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=es5).types @@ -27,3 +27,51 @@ for (let item of foo) { >value : string } +type Foo2 = [item?: Item]; +>Foo2 : [item?: Item | undefined] + +declare const foo2: Foo2; +>foo2 : Foo2 + +for (let item of foo2) { +>item : Item | undefined +>foo2 : Foo2 + + item.value; +>item.value : string +>item : Item | undefined +>value : string +} + +function fn1(t: [number, number?, number?]) { +>fn1 : (t: [number, number?, number?]) => void +>t : [number, (number | undefined)?, (number | undefined)?] + + for (let num of t) { +>num : number | undefined +>t : [number, (number | undefined)?, (number | undefined)?] + + num.toString() +>num.toString() : string +>num.toString : (radix?: number | undefined) => string +>num : number | undefined +>toString : (radix?: number | undefined) => string + } +} + +function fn2(t: [a: number, b?: number, c?: number]) { +>fn2 : (t: [a: number, b?: number, c?: number]) => void +>t : [a: number, b?: number | undefined, c?: number | undefined] + + for (let num of t) { +>num : number | undefined +>t : [a: number, b?: number | undefined, c?: number | undefined] + + num.toString() +>num.toString() : string +>num.toString : (radix?: number | undefined) => string +>num : number | undefined +>toString : (radix?: number | undefined) => string + } +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).errors.txt b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).errors.txt index 166d2bed58d39..0bd718f342d0f 100644 --- a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).errors.txt +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).errors.txt @@ -1,7 +1,10 @@ -forOfOptionalTupleMember.ts(12,3): error TS18048: 'item' is possibly 'undefined'. +forOfOptionalTupleMember.ts(10,3): error TS18048: 'item' is possibly 'undefined'. +forOfOptionalTupleMember.ts(16,3): error TS18048: 'item' is possibly 'undefined'. +forOfOptionalTupleMember.ts(21,5): error TS18048: 'num' is possibly 'undefined'. +forOfOptionalTupleMember.ts(27,5): error TS18048: 'num' is possibly 'undefined'. -==== forOfOptionalTupleMember.ts (1 errors) ==== +==== forOfOptionalTupleMember.ts (4 errors) ==== // repro from https://github.com/microsoft/TypeScript/issues/54302 type Item = { @@ -9,12 +12,34 @@ forOfOptionalTupleMember.ts(12,3): error TS18048: 'item' is possibly 'undefined' }; type Foo = [Item?]; - declare const foo: Foo; - for (let item of foo) { item.value; ~~~~ !!! error TS18048: 'item' is possibly 'undefined'. } + + type Foo2 = [item?: Item]; + declare const foo2: Foo2; + for (let item of foo2) { + item.value; + ~~~~ +!!! error TS18048: 'item' is possibly 'undefined'. + } + + function fn1(t: [number, number?, number?]) { + for (let num of t) { + num.toString() + ~~~ +!!! error TS18048: 'num' is possibly 'undefined'. + } + } + + function fn2(t: [a: number, b?: number, c?: number]) { + for (let num of t) { + num.toString() + ~~~ +!!! error TS18048: 'num' is possibly 'undefined'. + } + } \ No newline at end of file diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).symbols b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).symbols index 32d94a8c8f21e..9c9a3b4bb277a 100644 --- a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).symbols +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).symbols @@ -16,16 +16,64 @@ type Foo = [Item?]; >Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) declare const foo: Foo; ->foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 7, 13)) >Foo : Symbol(Foo, Decl(forOfOptionalTupleMember.ts, 4, 2)) for (let item of foo) { ->item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) ->foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 8, 8)) +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 7, 13)) item.value; >item.value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) ->item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 8, 8)) >value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) } +type Foo2 = [item?: Item]; +>Foo2 : Symbol(Foo2, Decl(forOfOptionalTupleMember.ts, 10, 1)) +>Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) + +declare const foo2: Foo2; +>foo2 : Symbol(foo2, Decl(forOfOptionalTupleMember.ts, 13, 13)) +>Foo2 : Symbol(Foo2, Decl(forOfOptionalTupleMember.ts, 10, 1)) + +for (let item of foo2) { +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 14, 8)) +>foo2 : Symbol(foo2, Decl(forOfOptionalTupleMember.ts, 13, 13)) + + item.value; +>item.value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 14, 8)) +>value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +} + +function fn1(t: [number, number?, number?]) { +>fn1 : Symbol(fn1, Decl(forOfOptionalTupleMember.ts, 16, 1)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 18, 13)) + + for (let num of t) { +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 19, 10)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 18, 13)) + + num.toString() +>num.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 19, 10)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + } +} + +function fn2(t: [a: number, b?: number, c?: number]) { +>fn2 : Symbol(fn2, Decl(forOfOptionalTupleMember.ts, 22, 1)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 24, 13)) + + for (let num of t) { +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 25, 10)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 24, 13)) + + num.toString() +>num.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 25, 10)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + } +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).types b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).types index ddfd8cbdfb05c..9d785a30ae155 100644 --- a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).types +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=false,target=esnext).types @@ -27,3 +27,51 @@ for (let item of foo) { >value : string } +type Foo2 = [item?: Item]; +>Foo2 : [item?: Item | undefined] + +declare const foo2: Foo2; +>foo2 : Foo2 + +for (let item of foo2) { +>item : Item | undefined +>foo2 : Foo2 + + item.value; +>item.value : string +>item : Item | undefined +>value : string +} + +function fn1(t: [number, number?, number?]) { +>fn1 : (t: [number, number?, number?]) => void +>t : [number, (number | undefined)?, (number | undefined)?] + + for (let num of t) { +>num : number | undefined +>t : [number, (number | undefined)?, (number | undefined)?] + + num.toString() +>num.toString() : string +>num.toString : (radix?: number | undefined) => string +>num : number | undefined +>toString : (radix?: number | undefined) => string + } +} + +function fn2(t: [a: number, b?: number, c?: number]) { +>fn2 : (t: [a: number, b?: number, c?: number]) => void +>t : [a: number, b?: number | undefined, c?: number | undefined] + + for (let num of t) { +>num : number | undefined +>t : [a: number, b?: number | undefined, c?: number | undefined] + + num.toString() +>num.toString() : string +>num.toString : (radix?: number | undefined) => string +>num : number | undefined +>toString : (radix?: number | undefined) => string + } +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).symbols b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).symbols index 32d94a8c8f21e..9c9a3b4bb277a 100644 --- a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).symbols +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).symbols @@ -16,16 +16,64 @@ type Foo = [Item?]; >Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) declare const foo: Foo; ->foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 7, 13)) >Foo : Symbol(Foo, Decl(forOfOptionalTupleMember.ts, 4, 2)) for (let item of foo) { ->item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) ->foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 8, 8)) +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 7, 13)) item.value; >item.value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) ->item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 8, 8)) >value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) } +type Foo2 = [item?: Item]; +>Foo2 : Symbol(Foo2, Decl(forOfOptionalTupleMember.ts, 10, 1)) +>Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) + +declare const foo2: Foo2; +>foo2 : Symbol(foo2, Decl(forOfOptionalTupleMember.ts, 13, 13)) +>Foo2 : Symbol(Foo2, Decl(forOfOptionalTupleMember.ts, 10, 1)) + +for (let item of foo2) { +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 14, 8)) +>foo2 : Symbol(foo2, Decl(forOfOptionalTupleMember.ts, 13, 13)) + + item.value; +>item.value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 14, 8)) +>value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +} + +function fn1(t: [number, number?, number?]) { +>fn1 : Symbol(fn1, Decl(forOfOptionalTupleMember.ts, 16, 1)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 18, 13)) + + for (let num of t) { +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 19, 10)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 18, 13)) + + num.toString() +>num.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 19, 10)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + } +} + +function fn2(t: [a: number, b?: number, c?: number]) { +>fn2 : Symbol(fn2, Decl(forOfOptionalTupleMember.ts, 22, 1)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 24, 13)) + + for (let num of t) { +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 25, 10)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 24, 13)) + + num.toString() +>num.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 25, 10)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + } +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).types b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).types index 7e7574e33081c..7bdcfc84dc59c 100644 --- a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).types +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=es5).types @@ -27,3 +27,51 @@ for (let item of foo) { >value : string } +type Foo2 = [item?: Item]; +>Foo2 : [item?: Item] + +declare const foo2: Foo2; +>foo2 : Foo2 + +for (let item of foo2) { +>item : Item +>foo2 : Foo2 + + item.value; +>item.value : string +>item : Item +>value : string +} + +function fn1(t: [number, number?, number?]) { +>fn1 : (t: [number, number?, number?]) => void +>t : [number, number?, number?] + + for (let num of t) { +>num : number +>t : [number, number?, number?] + + num.toString() +>num.toString() : string +>num.toString : (radix?: number | undefined) => string +>num : number +>toString : (radix?: number | undefined) => string + } +} + +function fn2(t: [a: number, b?: number, c?: number]) { +>fn2 : (t: [a: number, b?: number, c?: number]) => void +>t : [a: number, b?: number, c?: number] + + for (let num of t) { +>num : number +>t : [a: number, b?: number, c?: number] + + num.toString() +>num.toString() : string +>num.toString : (radix?: number | undefined) => string +>num : number +>toString : (radix?: number | undefined) => string + } +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).symbols b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).symbols index 32d94a8c8f21e..9c9a3b4bb277a 100644 --- a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).symbols +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).symbols @@ -16,16 +16,64 @@ type Foo = [Item?]; >Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) declare const foo: Foo; ->foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 7, 13)) >Foo : Symbol(Foo, Decl(forOfOptionalTupleMember.ts, 4, 2)) for (let item of foo) { ->item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) ->foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 8, 13)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 8, 8)) +>foo : Symbol(foo, Decl(forOfOptionalTupleMember.ts, 7, 13)) item.value; >item.value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) ->item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 10, 8)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 8, 8)) >value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) } +type Foo2 = [item?: Item]; +>Foo2 : Symbol(Foo2, Decl(forOfOptionalTupleMember.ts, 10, 1)) +>Item : Symbol(Item, Decl(forOfOptionalTupleMember.ts, 0, 0)) + +declare const foo2: Foo2; +>foo2 : Symbol(foo2, Decl(forOfOptionalTupleMember.ts, 13, 13)) +>Foo2 : Symbol(Foo2, Decl(forOfOptionalTupleMember.ts, 10, 1)) + +for (let item of foo2) { +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 14, 8)) +>foo2 : Symbol(foo2, Decl(forOfOptionalTupleMember.ts, 13, 13)) + + item.value; +>item.value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +>item : Symbol(item, Decl(forOfOptionalTupleMember.ts, 14, 8)) +>value : Symbol(value, Decl(forOfOptionalTupleMember.ts, 2, 13)) +} + +function fn1(t: [number, number?, number?]) { +>fn1 : Symbol(fn1, Decl(forOfOptionalTupleMember.ts, 16, 1)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 18, 13)) + + for (let num of t) { +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 19, 10)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 18, 13)) + + num.toString() +>num.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 19, 10)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + } +} + +function fn2(t: [a: number, b?: number, c?: number]) { +>fn2 : Symbol(fn2, Decl(forOfOptionalTupleMember.ts, 22, 1)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 24, 13)) + + for (let num of t) { +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 25, 10)) +>t : Symbol(t, Decl(forOfOptionalTupleMember.ts, 24, 13)) + + num.toString() +>num.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>num : Symbol(num, Decl(forOfOptionalTupleMember.ts, 25, 10)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + } +} + diff --git a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).types b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).types index 7e7574e33081c..7bdcfc84dc59c 100644 --- a/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).types +++ b/tests/baselines/reference/forOfOptionalTupleMember(exactoptionalpropertytypes=true,target=esnext).types @@ -27,3 +27,51 @@ for (let item of foo) { >value : string } +type Foo2 = [item?: Item]; +>Foo2 : [item?: Item] + +declare const foo2: Foo2; +>foo2 : Foo2 + +for (let item of foo2) { +>item : Item +>foo2 : Foo2 + + item.value; +>item.value : string +>item : Item +>value : string +} + +function fn1(t: [number, number?, number?]) { +>fn1 : (t: [number, number?, number?]) => void +>t : [number, number?, number?] + + for (let num of t) { +>num : number +>t : [number, number?, number?] + + num.toString() +>num.toString() : string +>num.toString : (radix?: number | undefined) => string +>num : number +>toString : (radix?: number | undefined) => string + } +} + +function fn2(t: [a: number, b?: number, c?: number]) { +>fn2 : (t: [a: number, b?: number, c?: number]) => void +>t : [a: number, b?: number, c?: number] + + for (let num of t) { +>num : number +>t : [a: number, b?: number, c?: number] + + num.toString() +>num.toString() : string +>num.toString : (radix?: number | undefined) => string +>num : number +>toString : (radix?: number | undefined) => string + } +} + diff --git a/tests/baselines/reference/strictOptionalProperties1.errors.txt b/tests/baselines/reference/strictOptionalProperties1.errors.txt index 237279463390c..fe65257cf80ce 100644 --- a/tests/baselines/reference/strictOptionalProperties1.errors.txt +++ b/tests/baselines/reference/strictOptionalProperties1.errors.txt @@ -7,6 +7,12 @@ strictOptionalProperties1.ts(53,5): error TS2412: Type 'undefined' is not assign strictOptionalProperties1.ts(60,5): error TS2322: Type 'undefined' is not assignable to type 'string'. strictOptionalProperties1.ts(64,5): error TS2322: Type '[number, string?, string?]' is not assignable to type '[number, string?]'. Target allows only 2 element(s) but source may have more. +strictOptionalProperties1.ts(71,5): error TS2322: Type '[number, never?]' is not assignable to type '[number, string?, boolean?]'. + Type at position 1 in source is not compatible with type at position 1 in target. + Type 'undefined' is not assignable to type 'string'. +strictOptionalProperties1.ts(72,5): error TS2322: Type '[number, never?, never?]' is not assignable to type '[number, string?, boolean?]'. + Type at position 1 in source is not compatible with type at position 1 in target. + Type 'undefined' is not assignable to type 'string'. strictOptionalProperties1.ts(73,5): error TS2322: Type '[number, never?, never?, never?]' is not assignable to type '[number, string?, boolean?]'. Target allows only 3 element(s) but source may have more. strictOptionalProperties1.ts(74,5): error TS2322: Type '[never?, never?, true?]' is not assignable to type '[number, string?, boolean?]'. @@ -47,7 +53,7 @@ strictOptionalProperties1.ts(211,1): error TS2322: Type 'string | boolean | unde Type 'undefined' is not assignable to type '{ [x: string]: string | number; }'. -==== strictOptionalProperties1.ts (23 errors) ==== +==== strictOptionalProperties1.ts (25 errors) ==== function f1(obj: { a?: string, b?: string | undefined }) { let a = obj.a; // string | undefined let b = obj.b; // string | undefined @@ -135,7 +141,15 @@ strictOptionalProperties1.ts(211,1): error TS2322: Type 'string | boolean | unde t = [42, 'abc']; t = [42, 'abc', true]; t = [42, ,]; + ~ +!!! error TS2322: Type '[number, never?]' is not assignable to type '[number, string?, boolean?]'. +!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target. +!!! error TS2322: Type 'undefined' is not assignable to type 'string'. t = [42, , ,]; + ~ +!!! error TS2322: Type '[number, never?, never?]' is not assignable to type '[number, string?, boolean?]'. +!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target. +!!! error TS2322: Type 'undefined' is not assignable to type 'string'. t = [42, , , ,]; // Error ~ !!! error TS2322: Type '[number, never?, never?, never?]' is not assignable to type '[number, string?, boolean?]'. diff --git a/tests/cases/compiler/forOfOptionalTupleMember.ts b/tests/cases/compiler/forOfOptionalTupleMember.ts index 3f5525124938b..72921295ed17a 100644 --- a/tests/cases/compiler/forOfOptionalTupleMember.ts +++ b/tests/cases/compiler/forOfOptionalTupleMember.ts @@ -10,9 +10,25 @@ type Item = { }; type Foo = [Item?]; - declare const foo: Foo; - for (let item of foo) { item.value; } + +type Foo2 = [item?: Item]; +declare const foo2: Foo2; +for (let item of foo2) { + item.value; +} + +function fn1(t: [number, number?, number?]) { + for (let num of t) { + num.toString() + } +} + +function fn2(t: [a: number, b?: number, c?: number]) { + for (let num of t) { + num.toString() + } +} From 3407b6bf37b128439beae944de7ec298f8c0f517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 1 Sep 2023 23:58:47 +0200 Subject: [PATCH 4/6] Remove redundant `removeMissingType` calls --- src/compiler/checker.ts | 24 ++++------- .../strictOptionalProperties1.errors.txt | 34 +++++++--------- .../reference/strictOptionalProperties1.types | 40 +++++++++---------- 3 files changed, 42 insertions(+), 56 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c2d025013790f..6d07bc653c5ff 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6982,7 +6982,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function typeReferenceToTypeNode(type: TypeReference) { - let typeArguments: readonly Type[] = getTypeArguments(type); + const typeArguments = getTypeArguments(type); if (type.target === globalArrayType || type.target === globalReadonlyArrayType) { if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) { const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context); @@ -6993,7 +6993,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type.target === globalArrayType ? arrayType : factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType); } else if (type.target.objectFlags & ObjectFlags.Tuple) { - typeArguments = sameMap(typeArguments, (t, i) => removeMissingType(t, !!((type.target as TupleType).elementFlags[i] & ElementFlags.Optional))); if (typeArguments.length > 0) { const arity = getTypeReferenceArity(type); const tupleConstituentNodes = mapToTypeNodes(typeArguments.slice(0, arity), context); @@ -19928,11 +19927,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let reportedError = false; for (const value of iterator) { const { errorNode: prop, innerExpression: next, nameType, errorMessage } = value; - let targetPropType = getBestMatchIndexedAccessTypeOrUndefined(source, target, nameType); + const targetPropType = getBestMatchIndexedAccessTypeOrUndefined(source, target, nameType); if (!targetPropType || targetPropType.flags & TypeFlags.IndexedAccess) continue; // Don't elaborate on indexes on generic variables - let sourcePropType = getIndexedAccessTypeOrUndefined(source, nameType); + const sourcePropType = getIndexedAccessTypeOrUndefined(source, nameType); if (!sourcePropType) continue; - const propName = getPropertyNameFromIndex(nameType, /*accessNode*/ undefined); if (!checkTypeRelatedTo(sourcePropType, targetPropType, relation, /*errorNode*/ undefined)) { const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); reportedError = true; @@ -19947,10 +19945,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resultObj.errors = [diag]; } else { - const targetIsOptional = !!(propName && (getPropertyOfType(target, propName) || unknownSymbol).flags & SymbolFlags.Optional); - const sourceIsOptional = !!(propName && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional); - targetPropType = removeMissingType(targetPropType, targetIsOptional); - sourcePropType = removeMissingType(sourcePropType, targetIsOptional && sourceIsOptional); const result = checkTypeRelatedTo(specificSource, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); if (result && specificSource !== sourcePropType) { // If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType @@ -29832,7 +29826,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 removeMissingType(getTypeArguments(t)[index], !!(t.target.elementFlags[index] && ElementFlags.Optional)); + return getTypeArguments(t)[index]; } // 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. @@ -30534,7 +30528,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const inConstContext = isConstContext(node); const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined); const inTupleContext = isSpreadIntoCallOrNew(node) || !!contextualType && someType(contextualType, isTupleLikeType); - let hasOmittedExpression = false; for (let i = 0; i < elementCount; i++) { const e = elements[i]; if (e.kind === SyntaxKind.SpreadElement) { @@ -30571,14 +30564,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else if (exactOptionalPropertyTypes && e.kind === SyntaxKind.OmittedExpression) { - hasOmittedExpression = true; - elementTypes.push(undefinedOrMissingType); - elementFlags.push(ElementFlags.Optional); + elementTypes.push(undefinedType); + elementFlags.push(ElementFlags.Required); } else { const type = checkExpressionForMutableLocation(e, checkMode, forceTuple); - elementTypes.push(addOptionality(type, /*isProperty*/ true, hasOmittedExpression)); - elementFlags.push(hasOmittedExpression ? ElementFlags.Optional : ElementFlags.Required); + elementTypes.push(type); + elementFlags.push(ElementFlags.Required); if (inTupleContext && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e)) { const inferenceContext = getInferenceContext(node); Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context diff --git a/tests/baselines/reference/strictOptionalProperties1.errors.txt b/tests/baselines/reference/strictOptionalProperties1.errors.txt index fe65257cf80ce..c8f58bb97e9b4 100644 --- a/tests/baselines/reference/strictOptionalProperties1.errors.txt +++ b/tests/baselines/reference/strictOptionalProperties1.errors.txt @@ -7,16 +7,17 @@ strictOptionalProperties1.ts(53,5): error TS2412: Type 'undefined' is not assign strictOptionalProperties1.ts(60,5): error TS2322: Type 'undefined' is not assignable to type 'string'. strictOptionalProperties1.ts(64,5): error TS2322: Type '[number, string?, string?]' is not assignable to type '[number, string?]'. Target allows only 2 element(s) but source may have more. -strictOptionalProperties1.ts(71,5): error TS2322: Type '[number, never?]' is not assignable to type '[number, string?, boolean?]'. +strictOptionalProperties1.ts(71,5): error TS2322: Type '[number, undefined]' is not assignable to type '[number, string?, boolean?]'. Type at position 1 in source is not compatible with type at position 1 in target. Type 'undefined' is not assignable to type 'string'. -strictOptionalProperties1.ts(72,5): error TS2322: Type '[number, never?, never?]' is not assignable to type '[number, string?, boolean?]'. +strictOptionalProperties1.ts(72,5): error TS2322: Type '[number, undefined, undefined]' is not assignable to type '[number, string?, boolean?]'. Type at position 1 in source is not compatible with type at position 1 in target. Type 'undefined' is not assignable to type 'string'. -strictOptionalProperties1.ts(73,5): error TS2322: Type '[number, never?, never?, never?]' is not assignable to type '[number, string?, boolean?]'. - Target allows only 3 element(s) but source may have more. -strictOptionalProperties1.ts(74,5): error TS2322: Type '[never?, never?, true?]' is not assignable to type '[number, string?, boolean?]'. - Source provides no match for required element at position 0 in target. +strictOptionalProperties1.ts(73,5): error TS2322: Type '[number, undefined, undefined, undefined]' is not assignable to type '[number, string?, boolean?]'. + Source has 4 element(s) but target allows only 3. +strictOptionalProperties1.ts(74,5): error TS2322: Type '[undefined, undefined, true]' is not assignable to type '[number, string?, boolean?]'. + Type at position 0 in source is not compatible with type at position 0 in target. + Type 'undefined' is not assignable to type 'number'. strictOptionalProperties1.ts(75,5): error TS2322: Type '[number, undefined, true]' is not assignable to type '[number, string?, boolean?]'. Type at position 1 in source is not compatible with type at position 1 in target. Type 'undefined' is not assignable to type 'string'. @@ -24,14 +25,10 @@ strictOptionalProperties1.ts(99,7): error TS2375: Type '{ foo: undefined; bar: s Types of property 'foo' are incompatible. Type 'undefined' is not assignable to type 'string'. strictOptionalProperties1.ts(105,7): error TS2322: Type '[number, undefined]' is not assignable to type '[number, string?, boolean?]'. - Type at position 1 in source is not compatible with type at position 1 in target. - Type 'undefined' is not assignable to type 'string'. strictOptionalProperties1.ts(106,7): error TS2322: Type '[number, string, undefined]' is not assignable to type '[number, string?, boolean?]'. Type at position 2 in source is not compatible with type at position 2 in target. Type 'undefined' is not assignable to type 'boolean'. strictOptionalProperties1.ts(107,7): error TS2322: Type '[number, undefined, undefined]' is not assignable to type '[number, string?, boolean?]'. - Type at position 1 in source is not compatible with type at position 1 in target. - Type 'undefined' is not assignable to type 'string'. strictOptionalProperties1.ts(111,7): error TS2375: Type '{ foo: undefined; }' is not assignable to type '{ foo?: number; }' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties. Types of property 'foo' are incompatible. Type 'undefined' is not assignable to type 'number'. @@ -142,22 +139,23 @@ strictOptionalProperties1.ts(211,1): error TS2322: Type 'string | boolean | unde t = [42, 'abc', true]; t = [42, ,]; ~ -!!! error TS2322: Type '[number, never?]' is not assignable to type '[number, string?, boolean?]'. +!!! error TS2322: Type '[number, undefined]' is not assignable to type '[number, string?, boolean?]'. !!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target. !!! error TS2322: Type 'undefined' is not assignable to type 'string'. t = [42, , ,]; ~ -!!! error TS2322: Type '[number, never?, never?]' is not assignable to type '[number, string?, boolean?]'. +!!! error TS2322: Type '[number, undefined, undefined]' is not assignable to type '[number, string?, boolean?]'. !!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target. !!! error TS2322: Type 'undefined' is not assignable to type 'string'. t = [42, , , ,]; // Error ~ -!!! error TS2322: Type '[number, never?, never?, never?]' is not assignable to type '[number, string?, boolean?]'. -!!! error TS2322: Target allows only 3 element(s) but source may have more. +!!! error TS2322: Type '[number, undefined, undefined, undefined]' is not assignable to type '[number, string?, boolean?]'. +!!! error TS2322: Source has 4 element(s) but target allows only 3. t = [, , true]; // Error ~ -!!! error TS2322: Type '[never?, never?, true?]' is not assignable to type '[number, string?, boolean?]'. -!!! error TS2322: Source provides no match for required element at position 0 in target. +!!! error TS2322: Type '[undefined, undefined, true]' is not assignable to type '[number, string?, boolean?]'. +!!! error TS2322: Type at position 0 in source is not compatible with type at position 0 in target. +!!! error TS2322: Type 'undefined' is not assignable to type 'number'. t = [42, undefined, true]; // Error ~ !!! error TS2322: Type '[number, undefined, true]' is not assignable to type '[number, string?, boolean?]'. @@ -199,8 +197,6 @@ strictOptionalProperties1.ts(211,1): error TS2322: Type 'string | boolean | unde const t2: [number, string?, boolean?] = [1, undefined]; ~~ !!! error TS2322: Type '[number, undefined]' is not assignable to type '[number, string?, boolean?]'. -!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target. -!!! error TS2322: Type 'undefined' is not assignable to type 'string'. const t3: [number, string?, boolean?] = [1, "string", undefined]; ~~ !!! error TS2322: Type '[number, string, undefined]' is not assignable to type '[number, string?, boolean?]'. @@ -209,8 +205,6 @@ strictOptionalProperties1.ts(211,1): error TS2322: Type 'string | boolean | unde const t4: [number, string?, boolean?] = [1, undefined, undefined]; ~~ !!! error TS2322: Type '[number, undefined, undefined]' is not assignable to type '[number, string?, boolean?]'. -!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target. -!!! error TS2322: Type 'undefined' is not assignable to type 'string'. // Example from #13195 diff --git a/tests/baselines/reference/strictOptionalProperties1.types b/tests/baselines/reference/strictOptionalProperties1.types index 6dfefa5876bf7..c5422b8b0f8b6 100644 --- a/tests/baselines/reference/strictOptionalProperties1.types +++ b/tests/baselines/reference/strictOptionalProperties1.types @@ -328,33 +328,33 @@ function f5(t: [number, string?, boolean?]) { >true : true t = [42, ,]; ->t = [42, ,] : [number, never?] +>t = [42, ,] : [number, undefined] >t : [number, string?, boolean?] ->[42, ,] : [number, never?] +>[42, ,] : [number, undefined] >42 : 42 > : undefined t = [42, , ,]; ->t = [42, , ,] : [number, never?, never?] +>t = [42, , ,] : [number, undefined, undefined] >t : [number, string?, boolean?] ->[42, , ,] : [number, never?, never?] +>[42, , ,] : [number, undefined, undefined] >42 : 42 > : undefined > : undefined t = [42, , , ,]; // Error ->t = [42, , , ,] : [number, never?, never?, never?] +>t = [42, , , ,] : [number, undefined, undefined, undefined] >t : [number, string?, boolean?] ->[42, , , ,] : [number, never?, never?, never?] +>[42, , , ,] : [number, undefined, undefined, undefined] >42 : 42 > : undefined > : undefined > : undefined t = [, , true]; // Error ->t = [, , true] : [never?, never?, true?] +>t = [, , true] : [undefined, undefined, true] >t : [number, string?, boolean?] ->[, , true] : [never?, never?, true?] +>[, , true] : [undefined, undefined, true] > : undefined > : undefined >true : true @@ -379,34 +379,34 @@ function f6() { >2 : 2 const t2 = [1, 2, ,] as const; ->t2 : readonly [1, 2, never?] ->[1, 2, ,] as const : readonly [1, 2, never?] ->[1, 2, ,] : readonly [1, 2, never?] +>t2 : readonly [1, 2, undefined] +>[1, 2, ,] as const : readonly [1, 2, undefined] +>[1, 2, ,] : readonly [1, 2, undefined] >1 : 1 >2 : 2 > : undefined const t3 = [1, 2, , ,] as const; ->t3 : readonly [1, 2, never?, never?] ->[1, 2, , ,] as const : readonly [1, 2, never?, never?] ->[1, 2, , ,] : readonly [1, 2, never?, never?] +>t3 : readonly [1, 2, undefined, undefined] +>[1, 2, , ,] as const : readonly [1, 2, undefined, undefined] +>[1, 2, , ,] : readonly [1, 2, undefined, undefined] >1 : 1 >2 : 2 > : undefined > : undefined const t4 = [1, , 2] as const; ->t4 : readonly [1, never?, 2?] ->[1, , 2] as const : readonly [1, never?, 2?] ->[1, , 2] : readonly [1, never?, 2?] +>t4 : readonly [1, undefined, 2] +>[1, , 2] as const : readonly [1, undefined, 2] +>[1, , 2] : readonly [1, undefined, 2] >1 : 1 > : undefined >2 : 2 const t5 = [1, , , 2] as const; ->t5 : readonly [1, never?, never?, 2?] ->[1, , , 2] as const : readonly [1, never?, never?, 2?] ->[1, , , 2] : readonly [1, never?, never?, 2?] +>t5 : readonly [1, undefined, undefined, 2] +>[1, , , 2] as const : readonly [1, undefined, undefined, 2] +>[1, , , 2] : readonly [1, undefined, undefined, 2] >1 : 1 > : undefined > : undefined From 3c846b45bd106664c7df0a71db0df19ab8d8a935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 3 Sep 2023 10:06:23 +0200 Subject: [PATCH 5/6] Revert part of the `removeMissingType` and add a test for it --- src/compiler/checker.ts | 9 +++++++-- .../strictOptionalPropertiesErrors1.errors.txt | 9 +++++++++ .../strictOptionalPropertiesErrors1.symbols | 10 ++++++++++ .../strictOptionalPropertiesErrors1.types | 14 ++++++++++++++ .../compiler/strictOptionalPropertiesErrors1.ts | 6 ++++++ 5 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/strictOptionalPropertiesErrors1.errors.txt create mode 100644 tests/baselines/reference/strictOptionalPropertiesErrors1.symbols create mode 100644 tests/baselines/reference/strictOptionalPropertiesErrors1.types create mode 100644 tests/cases/compiler/strictOptionalPropertiesErrors1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6d07bc653c5ff..74d071971cbd0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19927,10 +19927,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let reportedError = false; for (const value of iterator) { const { errorNode: prop, innerExpression: next, nameType, errorMessage } = value; - const targetPropType = getBestMatchIndexedAccessTypeOrUndefined(source, target, nameType); + let targetPropType = getBestMatchIndexedAccessTypeOrUndefined(source, target, nameType); if (!targetPropType || targetPropType.flags & TypeFlags.IndexedAccess) continue; // Don't elaborate on indexes on generic variables - const sourcePropType = getIndexedAccessTypeOrUndefined(source, nameType); + let sourcePropType = getIndexedAccessTypeOrUndefined(source, nameType); if (!sourcePropType) continue; + const propName = getPropertyNameFromIndex(nameType, /*accessNode*/ undefined); if (!checkTypeRelatedTo(sourcePropType, targetPropType, relation, /*errorNode*/ undefined)) { const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); reportedError = true; @@ -19945,6 +19946,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resultObj.errors = [diag]; } else { + const targetIsOptional = !!(propName && (getPropertyOfType(target, propName) || unknownSymbol).flags & SymbolFlags.Optional); + const sourceIsOptional = !!(propName && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional); + targetPropType = removeMissingType(targetPropType, targetIsOptional); + sourcePropType = removeMissingType(sourcePropType, targetIsOptional && sourceIsOptional); const result = checkTypeRelatedTo(specificSource, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); if (result && specificSource !== sourcePropType) { // If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType diff --git a/tests/baselines/reference/strictOptionalPropertiesErrors1.errors.txt b/tests/baselines/reference/strictOptionalPropertiesErrors1.errors.txt new file mode 100644 index 0000000000000..bcb6190a82bc5 --- /dev/null +++ b/tests/baselines/reference/strictOptionalPropertiesErrors1.errors.txt @@ -0,0 +1,9 @@ +strictOptionalPropertiesErrors1.ts(2,15): error TS2322: Type 'string' is not assignable to type 'number | boolean'. + + +==== strictOptionalPropertiesErrors1.ts (1 errors) ==== + function test1(arg: [string, (boolean | number)?]) {} + test1(['foo', 'bar']); + ~~~~~ +!!! error TS2322: Type 'string' is not assignable to type 'number | boolean'. + \ No newline at end of file diff --git a/tests/baselines/reference/strictOptionalPropertiesErrors1.symbols b/tests/baselines/reference/strictOptionalPropertiesErrors1.symbols new file mode 100644 index 0000000000000..4084e7965b7a8 --- /dev/null +++ b/tests/baselines/reference/strictOptionalPropertiesErrors1.symbols @@ -0,0 +1,10 @@ +//// [tests/cases/compiler/strictOptionalPropertiesErrors1.ts] //// + +=== strictOptionalPropertiesErrors1.ts === +function test1(arg: [string, (boolean | number)?]) {} +>test1 : Symbol(test1, Decl(strictOptionalPropertiesErrors1.ts, 0, 0)) +>arg : Symbol(arg, Decl(strictOptionalPropertiesErrors1.ts, 0, 15)) + +test1(['foo', 'bar']); +>test1 : Symbol(test1, Decl(strictOptionalPropertiesErrors1.ts, 0, 0)) + diff --git a/tests/baselines/reference/strictOptionalPropertiesErrors1.types b/tests/baselines/reference/strictOptionalPropertiesErrors1.types new file mode 100644 index 0000000000000..f066e3a0ee587 --- /dev/null +++ b/tests/baselines/reference/strictOptionalPropertiesErrors1.types @@ -0,0 +1,14 @@ +//// [tests/cases/compiler/strictOptionalPropertiesErrors1.ts] //// + +=== strictOptionalPropertiesErrors1.ts === +function test1(arg: [string, (boolean | number)?]) {} +>test1 : (arg: [string, (boolean | number)?]) => void +>arg : [string, (number | boolean)?] + +test1(['foo', 'bar']); +>test1(['foo', 'bar']) : void +>test1 : (arg: [string, (number | boolean)?]) => void +>['foo', 'bar'] : [string, string] +>'foo' : "foo" +>'bar' : "bar" + diff --git a/tests/cases/compiler/strictOptionalPropertiesErrors1.ts b/tests/cases/compiler/strictOptionalPropertiesErrors1.ts new file mode 100644 index 0000000000000..9ec79a739e2db --- /dev/null +++ b/tests/cases/compiler/strictOptionalPropertiesErrors1.ts @@ -0,0 +1,6 @@ +// @strict: true +// @exactOptionalPropertyTypes: true +// @noEmit: true + +function test1(arg: [string, (boolean | number)?]) {} +test1(['foo', 'bar']); From 068232314ac928c2aac3095569fc6c54e6adb9ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 4 Sep 2023 09:28:22 +0200 Subject: [PATCH 6/6] Add extra test case --- ...ionalPropertiesOmittedExpressions1.symbols | 20 +++++++++++++ ...ptionalPropertiesOmittedExpressions1.types | 28 +++++++++++++++++++ ...ctOptionalPropertiesOmittedExpressions1.ts | 9 ++++++ 3 files changed, 57 insertions(+) create mode 100644 tests/baselines/reference/strictOptionalPropertiesOmittedExpressions1.symbols create mode 100644 tests/baselines/reference/strictOptionalPropertiesOmittedExpressions1.types create mode 100644 tests/cases/compiler/strictOptionalPropertiesOmittedExpressions1.ts diff --git a/tests/baselines/reference/strictOptionalPropertiesOmittedExpressions1.symbols b/tests/baselines/reference/strictOptionalPropertiesOmittedExpressions1.symbols new file mode 100644 index 0000000000000..de57ea048ca8d --- /dev/null +++ b/tests/baselines/reference/strictOptionalPropertiesOmittedExpressions1.symbols @@ -0,0 +1,20 @@ +//// [tests/cases/compiler/strictOptionalPropertiesOmittedExpressions1.ts] //// + +=== strictOptionalPropertiesOmittedExpressions1.ts === +function test1(arg: [number, undefined, string]) {} +>test1 : Symbol(test1, Decl(strictOptionalPropertiesOmittedExpressions1.ts, 0, 0)) +>arg : Symbol(arg, Decl(strictOptionalPropertiesOmittedExpressions1.ts, 0, 15)) + +test1([10, , "foo"]); // ok +>test1 : Symbol(test1, Decl(strictOptionalPropertiesOmittedExpressions1.ts, 0, 0)) + +const test2 = ["foo", ,] as const; +>test2 : Symbol(test2, Decl(strictOptionalPropertiesOmittedExpressions1.ts, 3, 5)) +>const : Symbol(const) + +const length2 = test2.length; // 2 +>length2 : Symbol(length2, Decl(strictOptionalPropertiesOmittedExpressions1.ts, 4, 5)) +>test2.length : Symbol(length) +>test2 : Symbol(test2, Decl(strictOptionalPropertiesOmittedExpressions1.ts, 3, 5)) +>length : Symbol(length) + diff --git a/tests/baselines/reference/strictOptionalPropertiesOmittedExpressions1.types b/tests/baselines/reference/strictOptionalPropertiesOmittedExpressions1.types new file mode 100644 index 0000000000000..0af068b8c8605 --- /dev/null +++ b/tests/baselines/reference/strictOptionalPropertiesOmittedExpressions1.types @@ -0,0 +1,28 @@ +//// [tests/cases/compiler/strictOptionalPropertiesOmittedExpressions1.ts] //// + +=== strictOptionalPropertiesOmittedExpressions1.ts === +function test1(arg: [number, undefined, string]) {} +>test1 : (arg: [number, undefined, string]) => void +>arg : [number, undefined, string] + +test1([10, , "foo"]); // ok +>test1([10, , "foo"]) : void +>test1 : (arg: [number, undefined, string]) => void +>[10, , "foo"] : [number, undefined, string] +>10 : 10 +> : undefined +>"foo" : "foo" + +const test2 = ["foo", ,] as const; +>test2 : readonly ["foo", undefined] +>["foo", ,] as const : readonly ["foo", undefined] +>["foo", ,] : readonly ["foo", undefined] +>"foo" : "foo" +> : undefined + +const length2 = test2.length; // 2 +>length2 : 2 +>test2.length : 2 +>test2 : readonly ["foo", undefined] +>length : 2 + diff --git a/tests/cases/compiler/strictOptionalPropertiesOmittedExpressions1.ts b/tests/cases/compiler/strictOptionalPropertiesOmittedExpressions1.ts new file mode 100644 index 0000000000000..14eab880b981f --- /dev/null +++ b/tests/cases/compiler/strictOptionalPropertiesOmittedExpressions1.ts @@ -0,0 +1,9 @@ +// @strict: true +// @exactOptionalPropertyTypes: true +// @noEmit: true + +function test1(arg: [number, undefined, string]) {} +test1([10, , "foo"]); // ok + +const test2 = ["foo", ,] as const; +const length2 = test2.length; // 2