From 7706f3837eb9274a1508e0e6e3ac8bae3e034bcb Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 12 May 2016 14:59:45 -0700 Subject: [PATCH 01/11] Minor cleanup of getFlowTypeOfReference parameters --- src/compiler/checker.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f9b84e857dd11..71c19e1214a13 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7615,11 +7615,12 @@ namespace ts { getInitialTypeOfBindingElement(node); } - function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType: Type) { + function getFlowTypeOfReference(reference: Node, declaredType: Type, assumeInitialized: boolean) { let key: string; - if (!reference.flowNode || declaredType === initialType && !(declaredType.flags & TypeFlags.Narrowable)) { + if (!reference.flowNode || assumeInitialized && !(declaredType.flags & TypeFlags.Narrowable)) { return declaredType; } + const initialType = assumeInitialized ? declaredType : addNullableKind(declaredType, TypeFlags.Undefined); const visitedFlowStart = visitedFlowCount; const result = getTypeAtFlowNode(reference.flowNode); visitedFlowCount = visitedFlowStart; @@ -8093,11 +8094,11 @@ namespace ts { return type; } const declaration = localOrExportSymbol.valueDeclaration; - const defaultsToDeclaredType = !strictNullChecks || type.flags & TypeFlags.Any || !declaration || + const assumeInitialized = !strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || !declaration || getRootDeclaration(declaration).kind === SyntaxKind.Parameter || isInAmbientContext(declaration) || getContainingFunctionOrModule(declaration) !== getContainingFunctionOrModule(node); - const flowType = getFlowTypeOfReference(node, type, defaultsToDeclaredType ? type : addNullableKind(type, TypeFlags.Undefined)); - if (strictNullChecks && !(type.flags & TypeFlags.Any) && !(getNullableKind(type) & TypeFlags.Undefined) && getNullableKind(flowType) & TypeFlags.Undefined) { + const flowType = getFlowTypeOfReference(node, type, assumeInitialized); + if (!assumeInitialized && !(getNullableKind(type) & TypeFlags.Undefined) && getNullableKind(flowType) & TypeFlags.Undefined) { error(node, Diagnostics.Variable_0_is_used_before_being_assigned, symbolToString(symbol)); // Return the declared type to reduce follow-on errors return type; @@ -8345,7 +8346,7 @@ namespace ts { if (isClassLike(container.parent)) { const symbol = getSymbolOfNode(container.parent); const type = container.flags & NodeFlags.Static ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol)).thisType; - return getFlowTypeOfReference(node, type, type); + return getFlowTypeOfReference(node, type, /*assumeInitialized*/ true); } if (isInJavaScriptFile(node)) { @@ -9937,7 +9938,7 @@ namespace ts { return propType; } } - return getFlowTypeOfReference(node, propType, propType); + return getFlowTypeOfReference(node, propType, /*assumeInitialized*/ true); } function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean { From b90761cf43cebccb5bb4bfcd14608ba94226f604 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 14 May 2016 13:34:00 -0700 Subject: [PATCH 02/11] Allow class properties and methods to be declared optional using '?' --- src/compiler/checker.ts | 17 ++++++++--------- src/compiler/diagnosticMessages.json | 4 ---- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 71c19e1214a13..0f057e6166736 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3216,7 +3216,9 @@ namespace ts { function getTypeOfFuncClassEnumModule(symbol: Symbol): Type { const links = getSymbolLinks(symbol); if (!links.type) { - links.type = createObjectType(TypeFlags.Anonymous, symbol); + const type = createObjectType(TypeFlags.Anonymous, symbol); + links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ? + addNullableKind(type, TypeFlags.Undefined) : type; } return links.type; } @@ -9921,7 +9923,8 @@ namespace ts { } const propType = getTypeOfSymbol(prop); - if (node.kind !== SyntaxKind.PropertyAccessExpression || !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) || isAssignmentTarget(node)) { + if (node.kind !== SyntaxKind.PropertyAccessExpression || isAssignmentTarget(node) || + !(propType.flags & TypeFlags.Union) && !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor))) { return propType; } const leftmostNode = getLeftmostIdentifierOrThis(node); @@ -13396,7 +13399,7 @@ namespace ts { // Abstract methods can't have an implementation -- in particular, they don't need one. if (!isExportSymbolInsideModule && lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body && - !(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract)) { + !(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract) && !lastSeenNonAmbientDeclaration.questionToken) { reportImplementationExpectedError(lastSeenNonAmbientDeclaration); } @@ -18290,7 +18293,7 @@ namespace ts { } if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) { - if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional)) { + if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional)) { return true; } else if (node.body === undefined) { @@ -18299,9 +18302,6 @@ namespace ts { } if (isClassLike(node.parent)) { - if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional)) { - return true; - } // Technically, computed properties in ambient contexts is disallowed // for property declarations and accessors too, not just methods. // However, property declarations disallow computed names in general, @@ -18523,8 +18523,7 @@ namespace ts { function checkGrammarProperty(node: PropertyDeclaration) { if (isClassLike(node.parent)) { - if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional) || - checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_a_class_property_declaration_must_directly_refer_to_a_built_in_symbol)) { + if (checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_a_class_property_declaration_must_directly_refer_to_a_built_in_symbol)) { return true; } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 899b4292f04d1..cb347234ec7ed 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -315,10 +315,6 @@ "category": "Error", "code": 1110 }, - "A class member cannot be declared optional.": { - "category": "Error", - "code": 1112 - }, "A 'default' clause cannot appear more than once in a 'switch' statement.": { "category": "Error", "code": 1113 From 20e2be2d51f765e760b6668174976e9ac2ef2389 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 14 May 2016 13:34:54 -0700 Subject: [PATCH 03/11] Properly display optional methods in language service --- src/services/services.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/services/services.ts b/src/services/services.ts index 83f0d7152fd75..39dd688254d77 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -4541,8 +4541,10 @@ namespace ts { } // For properties, variables and local vars: show the type + // Also handle methods that have a union type (i.e. that may be undefined) if (symbolKind === ScriptElementKind.memberVariableElement || symbolFlags & SymbolFlags.Variable || + symbolFlags & SymbolFlags.Method && type.flags & TypeFlags.Union || symbolKind === ScriptElementKind.localVariableElement || isThisExpression) { displayParts.push(punctuationPart(SyntaxKind.ColonToken)); From b8d2f2da9e3481760d6f145157ddf16d6bce12dd Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 14 May 2016 13:35:11 -0700 Subject: [PATCH 04/11] Accepting new baselines --- .../classWithOptionalParameter.errors.txt | 26 ------------------- .../classWithOptionalParameter.symbols | 26 +++++++++++++++++++ .../classWithOptionalParameter.types | 26 +++++++++++++++++++ ...tLiteralMemberWithQuestionMark1.errors.txt | 4 +-- ...jectTypesWithOptionalProperties.errors.txt | 8 +----- 5 files changed, 55 insertions(+), 35 deletions(-) delete mode 100644 tests/baselines/reference/classWithOptionalParameter.errors.txt create mode 100644 tests/baselines/reference/classWithOptionalParameter.symbols create mode 100644 tests/baselines/reference/classWithOptionalParameter.types diff --git a/tests/baselines/reference/classWithOptionalParameter.errors.txt b/tests/baselines/reference/classWithOptionalParameter.errors.txt deleted file mode 100644 index 6e512c2a02e60..0000000000000 --- a/tests/baselines/reference/classWithOptionalParameter.errors.txt +++ /dev/null @@ -1,26 +0,0 @@ -tests/cases/conformance/types/namedTypes/classWithOptionalParameter.ts(4,6): error TS1112: A class member cannot be declared optional. -tests/cases/conformance/types/namedTypes/classWithOptionalParameter.ts(5,6): error TS1112: A class member cannot be declared optional. -tests/cases/conformance/types/namedTypes/classWithOptionalParameter.ts(9,6): error TS1112: A class member cannot be declared optional. -tests/cases/conformance/types/namedTypes/classWithOptionalParameter.ts(10,6): error TS1112: A class member cannot be declared optional. - - -==== tests/cases/conformance/types/namedTypes/classWithOptionalParameter.ts (4 errors) ==== - // classes do not permit optional parameters, these are errors - - class C { - x?: string; - ~ -!!! error TS1112: A class member cannot be declared optional. - f?() {} - ~ -!!! error TS1112: A class member cannot be declared optional. - } - - class C2 { - x?: T; - ~ -!!! error TS1112: A class member cannot be declared optional. - f?(x: T) {} - ~ -!!! error TS1112: A class member cannot be declared optional. - } \ No newline at end of file diff --git a/tests/baselines/reference/classWithOptionalParameter.symbols b/tests/baselines/reference/classWithOptionalParameter.symbols new file mode 100644 index 0000000000000..b85cd5d7a07b5 --- /dev/null +++ b/tests/baselines/reference/classWithOptionalParameter.symbols @@ -0,0 +1,26 @@ +=== tests/cases/conformance/types/namedTypes/classWithOptionalParameter.ts === +// classes do not permit optional parameters, these are errors + +class C { +>C : Symbol(C, Decl(classWithOptionalParameter.ts, 0, 0)) + + x?: string; +>x : Symbol(C.x, Decl(classWithOptionalParameter.ts, 2, 9)) + + f?() {} +>f : Symbol(C.f, Decl(classWithOptionalParameter.ts, 3, 15)) +} + +class C2 { +>C2 : Symbol(C2, Decl(classWithOptionalParameter.ts, 5, 1)) +>T : Symbol(T, Decl(classWithOptionalParameter.ts, 7, 9)) + + x?: T; +>x : Symbol(C2.x, Decl(classWithOptionalParameter.ts, 7, 13)) +>T : Symbol(T, Decl(classWithOptionalParameter.ts, 7, 9)) + + f?(x: T) {} +>f : Symbol(C2.f, Decl(classWithOptionalParameter.ts, 8, 10)) +>x : Symbol(x, Decl(classWithOptionalParameter.ts, 9, 7)) +>T : Symbol(T, Decl(classWithOptionalParameter.ts, 7, 9)) +} diff --git a/tests/baselines/reference/classWithOptionalParameter.types b/tests/baselines/reference/classWithOptionalParameter.types new file mode 100644 index 0000000000000..2c62aee6faba5 --- /dev/null +++ b/tests/baselines/reference/classWithOptionalParameter.types @@ -0,0 +1,26 @@ +=== tests/cases/conformance/types/namedTypes/classWithOptionalParameter.ts === +// classes do not permit optional parameters, these are errors + +class C { +>C : C + + x?: string; +>x : string + + f?() {} +>f : () => void +} + +class C2 { +>C2 : C2 +>T : T + + x?: T; +>x : T +>T : T + + f?(x: T) {} +>f : (x: T) => void +>x : T +>T : T +} diff --git a/tests/baselines/reference/objectLiteralMemberWithQuestionMark1.errors.txt b/tests/baselines/reference/objectLiteralMemberWithQuestionMark1.errors.txt index b10ba7011435e..f77bad8664cec 100644 --- a/tests/baselines/reference/objectLiteralMemberWithQuestionMark1.errors.txt +++ b/tests/baselines/reference/objectLiteralMemberWithQuestionMark1.errors.txt @@ -1,7 +1,7 @@ -tests/cases/compiler/objectLiteralMemberWithQuestionMark1.ts(1,14): error TS1112: A class member cannot be declared optional. +tests/cases/compiler/objectLiteralMemberWithQuestionMark1.ts(1,14): error TS1162: An object member cannot be declared optional. ==== tests/cases/compiler/objectLiteralMemberWithQuestionMark1.ts (1 errors) ==== var v = { foo?() { } } ~ -!!! error TS1112: A class member cannot be declared optional. \ No newline at end of file +!!! error TS1162: An object member cannot be declared optional. \ No newline at end of file diff --git a/tests/baselines/reference/objectTypesWithOptionalProperties.errors.txt b/tests/baselines/reference/objectTypesWithOptionalProperties.errors.txt index a2269c29d11d7..9fb2adc8c25d1 100644 --- a/tests/baselines/reference/objectTypesWithOptionalProperties.errors.txt +++ b/tests/baselines/reference/objectTypesWithOptionalProperties.errors.txt @@ -1,9 +1,7 @@ -tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties.ts(12,6): error TS1112: A class member cannot be declared optional. -tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties.ts(20,6): error TS1112: A class member cannot be declared optional. tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties.ts(24,6): error TS1162: An object member cannot be declared optional. -==== tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties.ts (3 errors) ==== +==== tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties.ts (1 errors) ==== // Basic uses of optional properties var a: { @@ -16,8 +14,6 @@ tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWith class C { x?: number; // error - ~ -!!! error TS1112: A class member cannot be declared optional. } interface I2 { @@ -26,8 +22,6 @@ tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWith class C2 { x?: T; // error - ~ -!!! error TS1112: A class member cannot be declared optional. } var b = { From 6b3fc7f310d63792b17888e8b942dfcd0f594583 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 16 May 2016 09:23:29 -0700 Subject: [PATCH 05/11] Remove nullability from function types in language service --- src/compiler/checker.ts | 1 + src/compiler/types.ts | 1 + src/services/services.ts | 10 ++++++---- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0f057e6166736..e2b7efeac67ad 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -79,6 +79,7 @@ namespace ts { getIndexTypeOfType, getBaseTypes, getReturnTypeOfSignature, + getNonNullableType, getSymbolsInScope, getSymbolAtLocation, getShorthandAssignmentValueSymbol, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3a5602717c156..d924ac168c8f0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1770,6 +1770,7 @@ namespace ts { getIndexTypeOfType(type: Type, kind: IndexKind): Type; getBaseTypes(type: InterfaceType): ObjectType[]; getReturnTypeOfSignature(signature: Signature): Type; + getNonNullableType(type: Type): Type; getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; getSymbolAtLocation(node: Node): Symbol; diff --git a/src/services/services.ts b/src/services/services.ts index 39dd688254d77..d8abb4e6842b8 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -50,6 +50,7 @@ namespace ts { getStringIndexType(): Type; getNumberIndexType(): Type; getBaseTypes(): ObjectType[]; + getNonNullableType(): Type; } export interface Signature { @@ -735,6 +736,9 @@ namespace ts { ? this.checker.getBaseTypes(this) : undefined; } + getNonNullableType(): Type { + return this.checker.getNonNullableType(this); + } } class SignatureObject implements Signature { @@ -4366,7 +4370,7 @@ namespace ts { (location.kind === SyntaxKind.ConstructorKeyword && location.parent.kind === SyntaxKind.Constructor)) { // At constructor keyword of constructor declaration // get the signature from the declaration and write it const functionDeclaration = location.parent; - const allSignatures = functionDeclaration.kind === SyntaxKind.Constructor ? type.getConstructSignatures() : type.getCallSignatures(); + const allSignatures = functionDeclaration.kind === SyntaxKind.Constructor ? type.getNonNullableType().getConstructSignatures() : type.getNonNullableType().getCallSignatures(); if (!typeChecker.isImplementationOfOverload(functionDeclaration)) { signature = typeChecker.getSignatureFromDeclaration(functionDeclaration); } @@ -4541,10 +4545,8 @@ namespace ts { } // For properties, variables and local vars: show the type - // Also handle methods that have a union type (i.e. that may be undefined) if (symbolKind === ScriptElementKind.memberVariableElement || symbolFlags & SymbolFlags.Variable || - symbolFlags & SymbolFlags.Method && type.flags & TypeFlags.Union || symbolKind === ScriptElementKind.localVariableElement || isThisExpression) { displayParts.push(punctuationPart(SyntaxKind.ColonToken)); @@ -4566,7 +4568,7 @@ namespace ts { symbolFlags & SymbolFlags.Signature || symbolFlags & SymbolFlags.Accessor || symbolKind === ScriptElementKind.memberFunctionElement) { - const allSignatures = type.getCallSignatures(); + const allSignatures = type.getNonNullableType().getCallSignatures(); addSignatureDisplayParts(allSignatures[0], allSignatures); } } From 3662c7b9cc6c278aa21d7587ddcfab74b8b4b80c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 16 May 2016 09:36:37 -0700 Subject: [PATCH 06/11] Adding test --- tests/baselines/reference/optionalMethods.js | 76 ++++++++ .../reference/optionalMethods.symbols | 160 ++++++++++++++++ .../baselines/reference/optionalMethods.types | 179 ++++++++++++++++++ .../types/namedTypes/optionalMethods.ts | 42 ++++ 4 files changed, 457 insertions(+) create mode 100644 tests/baselines/reference/optionalMethods.js create mode 100644 tests/baselines/reference/optionalMethods.symbols create mode 100644 tests/baselines/reference/optionalMethods.types create mode 100644 tests/cases/conformance/types/namedTypes/optionalMethods.ts diff --git a/tests/baselines/reference/optionalMethods.js b/tests/baselines/reference/optionalMethods.js new file mode 100644 index 0000000000000..1cf09a588a76a --- /dev/null +++ b/tests/baselines/reference/optionalMethods.js @@ -0,0 +1,76 @@ +//// [optionalMethods.ts] + +interface Foo { + a: number; + b?: number; + f(): number; + g?(): number; +} + +function test1(x: Foo) { + x.a; + x.b; + x.f; + x.g; + let f1 = x.f(); + let g1 = x.g && x.g(); + let g2 = x.g ? x.g() : 0; +} + +class Bar { + a: number; + b?: number; + f() { + return 1; + } + g?(): number; // Body of optional method can be omitted + h?() { + return 2; + } +} + +function test2(x: Bar) { + x.a; + x.b; + x.f; + x.g; + let f1 = x.f(); + let g1 = x.g && x.g(); + let g2 = x.g ? x.g() : 0; + let h1 = x.h && x.h(); + let h2 = x.h ? x.h() : 0; +} + + +//// [optionalMethods.js] +function test1(x) { + x.a; + x.b; + x.f; + x.g; + var f1 = x.f(); + var g1 = x.g && x.g(); + var g2 = x.g ? x.g() : 0; +} +var Bar = (function () { + function Bar() { + } + Bar.prototype.f = function () { + return 1; + }; + Bar.prototype.h = function () { + return 2; + }; + return Bar; +}()); +function test2(x) { + x.a; + x.b; + x.f; + x.g; + var f1 = x.f(); + var g1 = x.g && x.g(); + var g2 = x.g ? x.g() : 0; + var h1 = x.h && x.h(); + var h2 = x.h ? x.h() : 0; +} diff --git a/tests/baselines/reference/optionalMethods.symbols b/tests/baselines/reference/optionalMethods.symbols new file mode 100644 index 0000000000000..6b06e1902f47c --- /dev/null +++ b/tests/baselines/reference/optionalMethods.symbols @@ -0,0 +1,160 @@ +=== tests/cases/conformance/types/namedTypes/optionalMethods.ts === + +interface Foo { +>Foo : Symbol(Foo, Decl(optionalMethods.ts, 0, 0)) + + a: number; +>a : Symbol(Foo.a, Decl(optionalMethods.ts, 1, 15)) + + b?: number; +>b : Symbol(Foo.b, Decl(optionalMethods.ts, 2, 14)) + + f(): number; +>f : Symbol(Foo.f, Decl(optionalMethods.ts, 3, 15)) + + g?(): number; +>g : Symbol(Foo.g, Decl(optionalMethods.ts, 4, 16)) +} + +function test1(x: Foo) { +>test1 : Symbol(test1, Decl(optionalMethods.ts, 6, 1)) +>x : Symbol(x, Decl(optionalMethods.ts, 8, 15)) +>Foo : Symbol(Foo, Decl(optionalMethods.ts, 0, 0)) + + x.a; +>x.a : Symbol(Foo.a, Decl(optionalMethods.ts, 1, 15)) +>x : Symbol(x, Decl(optionalMethods.ts, 8, 15)) +>a : Symbol(Foo.a, Decl(optionalMethods.ts, 1, 15)) + + x.b; +>x.b : Symbol(Foo.b, Decl(optionalMethods.ts, 2, 14)) +>x : Symbol(x, Decl(optionalMethods.ts, 8, 15)) +>b : Symbol(Foo.b, Decl(optionalMethods.ts, 2, 14)) + + x.f; +>x.f : Symbol(Foo.f, Decl(optionalMethods.ts, 3, 15)) +>x : Symbol(x, Decl(optionalMethods.ts, 8, 15)) +>f : Symbol(Foo.f, Decl(optionalMethods.ts, 3, 15)) + + x.g; +>x.g : Symbol(Foo.g, Decl(optionalMethods.ts, 4, 16)) +>x : Symbol(x, Decl(optionalMethods.ts, 8, 15)) +>g : Symbol(Foo.g, Decl(optionalMethods.ts, 4, 16)) + + let f1 = x.f(); +>f1 : Symbol(f1, Decl(optionalMethods.ts, 13, 7)) +>x.f : Symbol(Foo.f, Decl(optionalMethods.ts, 3, 15)) +>x : Symbol(x, Decl(optionalMethods.ts, 8, 15)) +>f : Symbol(Foo.f, Decl(optionalMethods.ts, 3, 15)) + + let g1 = x.g && x.g(); +>g1 : Symbol(g1, Decl(optionalMethods.ts, 14, 7)) +>x.g : Symbol(Foo.g, Decl(optionalMethods.ts, 4, 16)) +>x : Symbol(x, Decl(optionalMethods.ts, 8, 15)) +>g : Symbol(Foo.g, Decl(optionalMethods.ts, 4, 16)) +>x.g : Symbol(Foo.g, Decl(optionalMethods.ts, 4, 16)) +>x : Symbol(x, Decl(optionalMethods.ts, 8, 15)) +>g : Symbol(Foo.g, Decl(optionalMethods.ts, 4, 16)) + + let g2 = x.g ? x.g() : 0; +>g2 : Symbol(g2, Decl(optionalMethods.ts, 15, 7)) +>x.g : Symbol(Foo.g, Decl(optionalMethods.ts, 4, 16)) +>x : Symbol(x, Decl(optionalMethods.ts, 8, 15)) +>g : Symbol(Foo.g, Decl(optionalMethods.ts, 4, 16)) +>x.g : Symbol(Foo.g, Decl(optionalMethods.ts, 4, 16)) +>x : Symbol(x, Decl(optionalMethods.ts, 8, 15)) +>g : Symbol(Foo.g, Decl(optionalMethods.ts, 4, 16)) +} + +class Bar { +>Bar : Symbol(Bar, Decl(optionalMethods.ts, 16, 1)) + + a: number; +>a : Symbol(Bar.a, Decl(optionalMethods.ts, 18, 11)) + + b?: number; +>b : Symbol(Bar.b, Decl(optionalMethods.ts, 19, 14)) + + f() { +>f : Symbol(Bar.f, Decl(optionalMethods.ts, 20, 15)) + + return 1; + } + g?(): number; // Body of optional method can be omitted +>g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) + + h?() { +>h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) + + return 2; + } +} + +function test2(x: Bar) { +>test2 : Symbol(test2, Decl(optionalMethods.ts, 28, 1)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>Bar : Symbol(Bar, Decl(optionalMethods.ts, 16, 1)) + + x.a; +>x.a : Symbol(Bar.a, Decl(optionalMethods.ts, 18, 11)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>a : Symbol(Bar.a, Decl(optionalMethods.ts, 18, 11)) + + x.b; +>x.b : Symbol(Bar.b, Decl(optionalMethods.ts, 19, 14)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>b : Symbol(Bar.b, Decl(optionalMethods.ts, 19, 14)) + + x.f; +>x.f : Symbol(Bar.f, Decl(optionalMethods.ts, 20, 15)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>f : Symbol(Bar.f, Decl(optionalMethods.ts, 20, 15)) + + x.g; +>x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) + + let f1 = x.f(); +>f1 : Symbol(f1, Decl(optionalMethods.ts, 35, 7)) +>x.f : Symbol(Bar.f, Decl(optionalMethods.ts, 20, 15)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>f : Symbol(Bar.f, Decl(optionalMethods.ts, 20, 15)) + + let g1 = x.g && x.g(); +>g1 : Symbol(g1, Decl(optionalMethods.ts, 36, 7)) +>x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) +>x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) + + let g2 = x.g ? x.g() : 0; +>g2 : Symbol(g2, Decl(optionalMethods.ts, 37, 7)) +>x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) +>x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) + + let h1 = x.h && x.h(); +>h1 : Symbol(h1, Decl(optionalMethods.ts, 38, 7)) +>x.h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) +>x.h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) + + let h2 = x.h ? x.h() : 0; +>h2 : Symbol(h2, Decl(optionalMethods.ts, 39, 7)) +>x.h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) +>x.h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) +>x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) +} + diff --git a/tests/baselines/reference/optionalMethods.types b/tests/baselines/reference/optionalMethods.types new file mode 100644 index 0000000000000..528a2e2354068 --- /dev/null +++ b/tests/baselines/reference/optionalMethods.types @@ -0,0 +1,179 @@ +=== tests/cases/conformance/types/namedTypes/optionalMethods.ts === + +interface Foo { +>Foo : Foo + + a: number; +>a : number + + b?: number; +>b : number | undefined + + f(): number; +>f : () => number + + g?(): number; +>g : (() => number) | undefined +} + +function test1(x: Foo) { +>test1 : (x: Foo) => void +>x : Foo +>Foo : Foo + + x.a; +>x.a : number +>x : Foo +>a : number + + x.b; +>x.b : number | undefined +>x : Foo +>b : number | undefined + + x.f; +>x.f : () => number +>x : Foo +>f : () => number + + x.g; +>x.g : (() => number) | undefined +>x : Foo +>g : (() => number) | undefined + + let f1 = x.f(); +>f1 : number +>x.f() : number +>x.f : () => number +>x : Foo +>f : () => number + + let g1 = x.g && x.g(); +>g1 : number | undefined +>x.g && x.g() : number | undefined +>x.g : (() => number) | undefined +>x : Foo +>g : (() => number) | undefined +>x.g() : number +>x.g : () => number +>x : Foo +>g : () => number + + let g2 = x.g ? x.g() : 0; +>g2 : number +>x.g ? x.g() : 0 : number +>x.g : (() => number) | undefined +>x : Foo +>g : (() => number) | undefined +>x.g() : number +>x.g : () => number +>x : Foo +>g : () => number +>0 : number +} + +class Bar { +>Bar : Bar + + a: number; +>a : number + + b?: number; +>b : number | undefined + + f() { +>f : () => number + + return 1; +>1 : number + } + g?(): number; // Body of optional method can be omitted +>g : (() => number) | undefined + + h?() { +>h : (() => number) | undefined + + return 2; +>2 : number + } +} + +function test2(x: Bar) { +>test2 : (x: Bar) => void +>x : Bar +>Bar : Bar + + x.a; +>x.a : number +>x : Bar +>a : number + + x.b; +>x.b : number | undefined +>x : Bar +>b : number | undefined + + x.f; +>x.f : () => number +>x : Bar +>f : () => number + + x.g; +>x.g : (() => number) | undefined +>x : Bar +>g : (() => number) | undefined + + let f1 = x.f(); +>f1 : number +>x.f() : number +>x.f : () => number +>x : Bar +>f : () => number + + let g1 = x.g && x.g(); +>g1 : number | undefined +>x.g && x.g() : number | undefined +>x.g : (() => number) | undefined +>x : Bar +>g : (() => number) | undefined +>x.g() : number +>x.g : () => number +>x : Bar +>g : () => number + + let g2 = x.g ? x.g() : 0; +>g2 : number +>x.g ? x.g() : 0 : number +>x.g : (() => number) | undefined +>x : Bar +>g : (() => number) | undefined +>x.g() : number +>x.g : () => number +>x : Bar +>g : () => number +>0 : number + + let h1 = x.h && x.h(); +>h1 : number | undefined +>x.h && x.h() : number | undefined +>x.h : (() => number) | undefined +>x : Bar +>h : (() => number) | undefined +>x.h() : number +>x.h : () => number +>x : Bar +>h : () => number + + let h2 = x.h ? x.h() : 0; +>h2 : number +>x.h ? x.h() : 0 : number +>x.h : (() => number) | undefined +>x : Bar +>h : (() => number) | undefined +>x.h() : number +>x.h : () => number +>x : Bar +>h : () => number +>0 : number +} + diff --git a/tests/cases/conformance/types/namedTypes/optionalMethods.ts b/tests/cases/conformance/types/namedTypes/optionalMethods.ts new file mode 100644 index 0000000000000..47cd72fbae75d --- /dev/null +++ b/tests/cases/conformance/types/namedTypes/optionalMethods.ts @@ -0,0 +1,42 @@ +// @strictNullChecks: true + +interface Foo { + a: number; + b?: number; + f(): number; + g?(): number; +} + +function test1(x: Foo) { + x.a; + x.b; + x.f; + x.g; + let f1 = x.f(); + let g1 = x.g && x.g(); + let g2 = x.g ? x.g() : 0; +} + +class Bar { + a: number; + b?: number; + f() { + return 1; + } + g?(): number; // Body of optional method can be omitted + h?() { + return 2; + } +} + +function test2(x: Bar) { + x.a; + x.b; + x.f; + x.g; + let f1 = x.f(); + let g1 = x.g && x.g(); + let g2 = x.g ? x.g() : 0; + let h1 = x.h && x.h(); + let h2 = x.h ? x.h() : 0; +} From d66377d12506955a423203fbd510fa12bbbc5e1e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 16 May 2016 13:33:33 -0700 Subject: [PATCH 07/11] Add optionality to properties declared with '?' and initializer --- src/compiler/checker.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e2b7efeac67ad..bdfbc90c3e2ac 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2886,6 +2886,10 @@ namespace ts { return undefined; } + function addOptionality(type: Type, optional: boolean): Type { + return strictNullChecks && optional ? addNullableKind(type, TypeFlags.Undefined) : type; + } + // Return the inferred type for a variable, parameter, or property declaration function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration): Type { if (declaration.flags & NodeFlags.JavaScriptFile) { @@ -2917,8 +2921,7 @@ namespace ts { // Use type from type annotation if one is present if (declaration.type) { - const type = getTypeFromTypeNode(declaration.type); - return strictNullChecks && declaration.questionToken ? addNullableKind(type, TypeFlags.Undefined) : type; + return addOptionality(getTypeFromTypeNode(declaration.type), /*optional*/ !!declaration.questionToken); } if (declaration.kind === SyntaxKind.Parameter) { @@ -2940,13 +2943,13 @@ namespace ts { ? getContextuallyTypedThisType(func) : getContextuallyTypedParameterType(declaration); if (type) { - return strictNullChecks && declaration.questionToken ? addNullableKind(type, TypeFlags.Undefined) : type; + return addOptionality(type, /*optional*/ !!declaration.questionToken); } } // Use the type of the initializer expression if one is present if (declaration.initializer) { - return checkExpressionCached(declaration.initializer); + return addOptionality(checkExpressionCached(declaration.initializer), /*optional*/ !!declaration.questionToken); } // If it is a short-hand property assignment, use the type of the identifier From a11f72f9ab5de52b0f7c1bd7fdeb87489ae9e7f3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 16 May 2016 13:34:54 -0700 Subject: [PATCH 08/11] Emit '?' for optional parameter property in declaration file --- src/compiler/declarationEmitter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index aceec9332277d..a94c9a58d2185 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -1129,7 +1129,7 @@ namespace ts { // what we want, namely the name expression enclosed in brackets. writeTextOfNode(currentText, node.name); // If optional property emit ? - if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && hasQuestionToken(node)) { + if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature || node.kind === SyntaxKind.Parameter) && hasQuestionToken(node)) { write("?"); } if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) { From 0292eaac4a49061897d5851d451737acdbb5a05b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 16 May 2016 13:36:39 -0700 Subject: [PATCH 09/11] Accepting new baselines --- tests/baselines/reference/declFileConstructors.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/declFileConstructors.js b/tests/baselines/reference/declFileConstructors.js index 44e816712fbcd..8e92b1a36aef6 100644 --- a/tests/baselines/reference/declFileConstructors.js +++ b/tests/baselines/reference/declFileConstructors.js @@ -247,7 +247,7 @@ export declare class ConstructorWithPrivateParameterProperty { constructor(x: string); } export declare class ConstructorWithOptionalParameterProperty { - x: string; + x?: string; constructor(x?: string); } export declare class ConstructorWithParameterInitializer { @@ -281,7 +281,7 @@ declare class GlobalConstructorWithPrivateParameterProperty { constructor(x: string); } declare class GlobalConstructorWithOptionalParameterProperty { - x: string; + x?: string; constructor(x?: string); } declare class GlobalConstructorWithParameterInitializer { From e82bbce28c9f2e4704133440ff9ab66948326219 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 16 May 2016 13:37:03 -0700 Subject: [PATCH 10/11] Fixing test --- .../reference/objectTypesWithOptionalProperties.errors.txt | 4 ++-- .../baselines/reference/objectTypesWithOptionalProperties.js | 4 ++-- .../methodSignatures/objectTypesWithOptionalProperties.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/baselines/reference/objectTypesWithOptionalProperties.errors.txt b/tests/baselines/reference/objectTypesWithOptionalProperties.errors.txt index 9fb2adc8c25d1..74057195c6449 100644 --- a/tests/baselines/reference/objectTypesWithOptionalProperties.errors.txt +++ b/tests/baselines/reference/objectTypesWithOptionalProperties.errors.txt @@ -13,7 +13,7 @@ tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWith } class C { - x?: number; // error + x?: number; // ok } interface I2 { @@ -21,7 +21,7 @@ tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWith } class C2 { - x?: T; // error + x?: T; // ok } var b = { diff --git a/tests/baselines/reference/objectTypesWithOptionalProperties.js b/tests/baselines/reference/objectTypesWithOptionalProperties.js index 98141c048dd0b..9b2ada010d920 100644 --- a/tests/baselines/reference/objectTypesWithOptionalProperties.js +++ b/tests/baselines/reference/objectTypesWithOptionalProperties.js @@ -10,7 +10,7 @@ interface I { } class C { - x?: number; // error + x?: number; // ok } interface I2 { @@ -18,7 +18,7 @@ interface I2 { } class C2 { - x?: T; // error + x?: T; // ok } var b = { diff --git a/tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties.ts b/tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties.ts index f80c3a5952db0..7c05ff09e5631 100644 --- a/tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties.ts +++ b/tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties.ts @@ -9,7 +9,7 @@ interface I { } class C { - x?: number; // error + x?: number; // ok } interface I2 { @@ -17,7 +17,7 @@ interface I2 { } class C2 { - x?: T; // error + x?: T; // ok } var b = { From 8498ef190e9382621ea4cfe4d392d878e5d052ac Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 16 May 2016 13:37:17 -0700 Subject: [PATCH 11/11] Adding more tests --- tests/baselines/reference/optionalMethods.js | 73 +++++++++- .../reference/optionalMethods.symbols | 133 ++++++++++++------ .../baselines/reference/optionalMethods.types | 47 +++++++ .../types/namedTypes/optionalMethods.ts | 16 +++ 4 files changed, 223 insertions(+), 46 deletions(-) diff --git a/tests/baselines/reference/optionalMethods.js b/tests/baselines/reference/optionalMethods.js index 1cf09a588a76a..42decf512e4d7 100644 --- a/tests/baselines/reference/optionalMethods.js +++ b/tests/baselines/reference/optionalMethods.js @@ -20,6 +20,8 @@ function test1(x: Foo) { class Bar { a: number; b?: number; + c? = 2; + constructor(public d?: number, public e = 10) {} f() { return 1; } @@ -32,6 +34,9 @@ class Bar { function test2(x: Bar) { x.a; x.b; + x.c; + x.d; + x.e; x.f; x.g; let f1 = x.f(); @@ -40,9 +45,24 @@ function test2(x: Bar) { let h1 = x.h && x.h(); let h2 = x.h ? x.h() : 0; } + +class Base { + a?: number; + f?(): number; +} + +class Derived extends Base { + a = 1; + f(): number { return 1; } +} //// [optionalMethods.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; function test1(x) { x.a; x.b; @@ -53,7 +73,11 @@ function test1(x) { var g2 = x.g ? x.g() : 0; } var Bar = (function () { - function Bar() { + function Bar(d, e) { + if (e === void 0) { e = 10; } + this.d = d; + this.e = e; + this.c = 2; } Bar.prototype.f = function () { return 1; @@ -66,6 +90,9 @@ var Bar = (function () { function test2(x) { x.a; x.b; + x.c; + x.d; + x.e; x.f; x.g; var f1 = x.f(); @@ -74,3 +101,47 @@ function test2(x) { var h1 = x.h && x.h(); var h2 = x.h ? x.h() : 0; } +var Base = (function () { + function Base() { + } + return Base; +}()); +var Derived = (function (_super) { + __extends(Derived, _super); + function Derived() { + _super.apply(this, arguments); + this.a = 1; + } + Derived.prototype.f = function () { return 1; }; + return Derived; +}(Base)); + + +//// [optionalMethods.d.ts] +interface Foo { + a: number; + b?: number; + f(): number; + g?(): number; +} +declare function test1(x: Foo): void; +declare class Bar { + d?: number; + e: number; + a: number; + b?: number; + c?: number | undefined; + constructor(d?: number, e?: number); + f(): number; + g?(): number; + h?(): number; +} +declare function test2(x: Bar): void; +declare class Base { + a?: number; + f?(): number; +} +declare class Derived extends Base { + a: number; + f(): number; +} diff --git a/tests/baselines/reference/optionalMethods.symbols b/tests/baselines/reference/optionalMethods.symbols index 6b06e1902f47c..55c5ec958da97 100644 --- a/tests/baselines/reference/optionalMethods.symbols +++ b/tests/baselines/reference/optionalMethods.symbols @@ -75,86 +75,129 @@ class Bar { b?: number; >b : Symbol(Bar.b, Decl(optionalMethods.ts, 19, 14)) + c? = 2; +>c : Symbol(Bar.c, Decl(optionalMethods.ts, 20, 15)) + + constructor(public d?: number, public e = 10) {} +>d : Symbol(Bar.d, Decl(optionalMethods.ts, 22, 16)) +>e : Symbol(Bar.e, Decl(optionalMethods.ts, 22, 34)) + f() { ->f : Symbol(Bar.f, Decl(optionalMethods.ts, 20, 15)) +>f : Symbol(Bar.f, Decl(optionalMethods.ts, 22, 52)) return 1; } g?(): number; // Body of optional method can be omitted ->g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) +>g : Symbol(Bar.g, Decl(optionalMethods.ts, 25, 5)) h?() { ->h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) +>h : Symbol(Bar.h, Decl(optionalMethods.ts, 26, 17)) return 2; } } function test2(x: Bar) { ->test2 : Symbol(test2, Decl(optionalMethods.ts, 28, 1)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>test2 : Symbol(test2, Decl(optionalMethods.ts, 30, 1)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) >Bar : Symbol(Bar, Decl(optionalMethods.ts, 16, 1)) x.a; >x.a : Symbol(Bar.a, Decl(optionalMethods.ts, 18, 11)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) >a : Symbol(Bar.a, Decl(optionalMethods.ts, 18, 11)) x.b; >x.b : Symbol(Bar.b, Decl(optionalMethods.ts, 19, 14)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) >b : Symbol(Bar.b, Decl(optionalMethods.ts, 19, 14)) + x.c; +>x.c : Symbol(Bar.c, Decl(optionalMethods.ts, 20, 15)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>c : Symbol(Bar.c, Decl(optionalMethods.ts, 20, 15)) + + x.d; +>x.d : Symbol(Bar.d, Decl(optionalMethods.ts, 22, 16)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>d : Symbol(Bar.d, Decl(optionalMethods.ts, 22, 16)) + + x.e; +>x.e : Symbol(Bar.e, Decl(optionalMethods.ts, 22, 34)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>e : Symbol(Bar.e, Decl(optionalMethods.ts, 22, 34)) + x.f; ->x.f : Symbol(Bar.f, Decl(optionalMethods.ts, 20, 15)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) ->f : Symbol(Bar.f, Decl(optionalMethods.ts, 20, 15)) +>x.f : Symbol(Bar.f, Decl(optionalMethods.ts, 22, 52)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>f : Symbol(Bar.f, Decl(optionalMethods.ts, 22, 52)) x.g; ->x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) ->g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) +>x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 25, 5)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>g : Symbol(Bar.g, Decl(optionalMethods.ts, 25, 5)) let f1 = x.f(); ->f1 : Symbol(f1, Decl(optionalMethods.ts, 35, 7)) ->x.f : Symbol(Bar.f, Decl(optionalMethods.ts, 20, 15)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) ->f : Symbol(Bar.f, Decl(optionalMethods.ts, 20, 15)) +>f1 : Symbol(f1, Decl(optionalMethods.ts, 40, 7)) +>x.f : Symbol(Bar.f, Decl(optionalMethods.ts, 22, 52)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>f : Symbol(Bar.f, Decl(optionalMethods.ts, 22, 52)) let g1 = x.g && x.g(); ->g1 : Symbol(g1, Decl(optionalMethods.ts, 36, 7)) ->x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) ->g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) ->x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) ->g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) +>g1 : Symbol(g1, Decl(optionalMethods.ts, 41, 7)) +>x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 25, 5)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>g : Symbol(Bar.g, Decl(optionalMethods.ts, 25, 5)) +>x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 25, 5)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>g : Symbol(Bar.g, Decl(optionalMethods.ts, 25, 5)) let g2 = x.g ? x.g() : 0; ->g2 : Symbol(g2, Decl(optionalMethods.ts, 37, 7)) ->x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) ->g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) ->x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) ->g : Symbol(Bar.g, Decl(optionalMethods.ts, 23, 5)) +>g2 : Symbol(g2, Decl(optionalMethods.ts, 42, 7)) +>x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 25, 5)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>g : Symbol(Bar.g, Decl(optionalMethods.ts, 25, 5)) +>x.g : Symbol(Bar.g, Decl(optionalMethods.ts, 25, 5)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>g : Symbol(Bar.g, Decl(optionalMethods.ts, 25, 5)) let h1 = x.h && x.h(); ->h1 : Symbol(h1, Decl(optionalMethods.ts, 38, 7)) ->x.h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) ->h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) ->x.h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) ->h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) +>h1 : Symbol(h1, Decl(optionalMethods.ts, 43, 7)) +>x.h : Symbol(Bar.h, Decl(optionalMethods.ts, 26, 17)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>h : Symbol(Bar.h, Decl(optionalMethods.ts, 26, 17)) +>x.h : Symbol(Bar.h, Decl(optionalMethods.ts, 26, 17)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>h : Symbol(Bar.h, Decl(optionalMethods.ts, 26, 17)) let h2 = x.h ? x.h() : 0; ->h2 : Symbol(h2, Decl(optionalMethods.ts, 39, 7)) ->x.h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) ->h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) ->x.h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) ->x : Symbol(x, Decl(optionalMethods.ts, 30, 15)) ->h : Symbol(Bar.h, Decl(optionalMethods.ts, 24, 17)) +>h2 : Symbol(h2, Decl(optionalMethods.ts, 44, 7)) +>x.h : Symbol(Bar.h, Decl(optionalMethods.ts, 26, 17)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>h : Symbol(Bar.h, Decl(optionalMethods.ts, 26, 17)) +>x.h : Symbol(Bar.h, Decl(optionalMethods.ts, 26, 17)) +>x : Symbol(x, Decl(optionalMethods.ts, 32, 15)) +>h : Symbol(Bar.h, Decl(optionalMethods.ts, 26, 17)) +} + +class Base { +>Base : Symbol(Base, Decl(optionalMethods.ts, 45, 1)) + + a?: number; +>a : Symbol(Base.a, Decl(optionalMethods.ts, 47, 12)) + + f?(): number; +>f : Symbol(Base.f, Decl(optionalMethods.ts, 48, 15)) +} + +class Derived extends Base { +>Derived : Symbol(Derived, Decl(optionalMethods.ts, 50, 1)) +>Base : Symbol(Base, Decl(optionalMethods.ts, 45, 1)) + + a = 1; +>a : Symbol(Derived.a, Decl(optionalMethods.ts, 52, 28)) + + f(): number { return 1; } +>f : Symbol(Derived.f, Decl(optionalMethods.ts, 53, 10)) } diff --git a/tests/baselines/reference/optionalMethods.types b/tests/baselines/reference/optionalMethods.types index 528a2e2354068..70fda27c01235 100644 --- a/tests/baselines/reference/optionalMethods.types +++ b/tests/baselines/reference/optionalMethods.types @@ -81,6 +81,15 @@ class Bar { b?: number; >b : number | undefined + c? = 2; +>c : number | undefined +>2 : number + + constructor(public d?: number, public e = 10) {} +>d : number | undefined +>e : number +>10 : number + f() { >f : () => number @@ -113,6 +122,21 @@ function test2(x: Bar) { >x : Bar >b : number | undefined + x.c; +>x.c : number | undefined +>x : Bar +>c : number | undefined + + x.d; +>x.d : number | undefined +>x : Bar +>d : number | undefined + + x.e; +>x.e : number +>x : Bar +>e : number + x.f; >x.f : () => number >x : Bar @@ -177,3 +201,26 @@ function test2(x: Bar) { >0 : number } +class Base { +>Base : Base + + a?: number; +>a : number | undefined + + f?(): number; +>f : (() => number) | undefined +} + +class Derived extends Base { +>Derived : Derived +>Base : Base + + a = 1; +>a : number +>1 : number + + f(): number { return 1; } +>f : () => number +>1 : number +} + diff --git a/tests/cases/conformance/types/namedTypes/optionalMethods.ts b/tests/cases/conformance/types/namedTypes/optionalMethods.ts index 47cd72fbae75d..932521425f9f6 100644 --- a/tests/cases/conformance/types/namedTypes/optionalMethods.ts +++ b/tests/cases/conformance/types/namedTypes/optionalMethods.ts @@ -1,4 +1,5 @@ // @strictNullChecks: true +// @declaration: true interface Foo { a: number; @@ -20,6 +21,8 @@ function test1(x: Foo) { class Bar { a: number; b?: number; + c? = 2; + constructor(public d?: number, public e = 10) {} f() { return 1; } @@ -32,6 +35,9 @@ class Bar { function test2(x: Bar) { x.a; x.b; + x.c; + x.d; + x.e; x.f; x.g; let f1 = x.f(); @@ -40,3 +46,13 @@ function test2(x: Bar) { let h1 = x.h && x.h(); let h2 = x.h ? x.h() : 0; } + +class Base { + a?: number; + f?(): number; +} + +class Derived extends Base { + a = 1; + f(): number { return 1; } +}