From 5c2eeb20b166d006e83f15b07af08fa85331e8db Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 28 Jun 2018 10:41:38 -0700 Subject: [PATCH] Destructuring declaration prefers type annotation type (#25282) * Destructuring declaration prefers type annotation type Previously, getTypeForBindingElement would always union the declarations type and the type of the default initializer. Now, if the declaration has a type annotation, it does not union with the initializer type. The type annotation's type is the one used. * Small cleanup in parentDeclarationHasTypeAnnotation * Refactoring based on PR comments * Combine getCombined*Flags into a single helper function Retain the individual functions since they are used a lot. * Remove unneeded temp --- src/compiler/checker.ts | 6 +- src/compiler/utilities.ts | 49 +++++-------- src/services/utilities.ts | 2 +- .../reference/api/tsserverlibrary.d.ts | 3 +- tests/baselines/reference/api/typescript.d.ts | 3 +- ...TypedBindingInitializerNegative.errors.txt | 67 ++++++++++++++++++ ...uallyTypedBindingInitializerNegative.types | 14 ++-- ...tructuringParameterDeclaration8.errors.txt | 42 +++++++++++ .../destructuringParameterDeclaration8.js | 33 +++++++++ ...destructuringParameterDeclaration8.symbols | 51 ++++++++++++++ .../destructuringParameterDeclaration8.types | 70 +++++++++++++++++++ ...structuringVariableDeclaration2.errors.txt | 9 ++- .../destructuringVariableDeclaration2.types | 2 +- ...rInDestructuringWithInitializer.errors.txt | 8 +-- ...ameterInDestructuringWithInitializer.types | 4 +- .../destructuringParameterDeclaration8.ts | 18 +++++ .../TypeScript-Node-Starter | 2 +- 17 files changed, 328 insertions(+), 55 deletions(-) create mode 100644 tests/baselines/reference/contextuallyTypedBindingInitializerNegative.errors.txt create mode 100644 tests/baselines/reference/destructuringParameterDeclaration8.errors.txt create mode 100644 tests/baselines/reference/destructuringParameterDeclaration8.js create mode 100644 tests/baselines/reference/destructuringParameterDeclaration8.symbols create mode 100644 tests/baselines/reference/destructuringParameterDeclaration8.types create mode 100644 tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b20ab654de2..c9eb0176c45 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4161,7 +4161,7 @@ namespace ts { } const parent = getDeclarationContainer(node); // If the node is not exported or it is not ambient module element (except import declaration) - if (!(getCombinedModifierFlags(node) & ModifierFlags.Export) && + if (!(getCombinedModifierFlags(node as Declaration) & ModifierFlags.Export) && !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && parent.flags & NodeFlags.Ambient)) { return isGlobalSourceFile(parent); } @@ -4525,7 +4525,7 @@ namespace ts { if (strictNullChecks && declaration.initializer && !(getFalsyFlags(checkExpressionCached(declaration.initializer)) & TypeFlags.Undefined)) { type = getTypeWithFacts(type, TypeFacts.NEUndefined); } - return declaration.initializer ? + return declaration.initializer && !getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration)) ? getUnionType([type, checkExpressionCached(declaration.initializer)], UnionReduction.Subtype) : type; } @@ -22096,7 +22096,7 @@ namespace ts { return hasModifier(node, ModifierFlags.Private) && !!(node.flags & NodeFlags.Ambient); } - function getEffectiveDeclarationFlags(n: Node, flagsToCheck: ModifierFlags): ModifierFlags { + function getEffectiveDeclarationFlags(n: Declaration, flagsToCheck: ModifierFlags): ModifierFlags { let flags = getCombinedModifierFlags(n); // children of classes (even ambient classes) should not be marked as ambient or export diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index e3c0fd87606..40cb2cc96e8 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -903,7 +903,7 @@ namespace ts { export function isConst(node: Node): boolean { return !!(getCombinedNodeFlags(node) & NodeFlags.Const) - || !!(getCombinedModifierFlags(node) & ModifierFlags.Const); + || !!(isDeclaration(node) && getCombinedModifierFlags(node) & ModifierFlags.Const); } export function isLet(node: Node): boolean { @@ -4605,33 +4605,36 @@ namespace ts { return isEmptyBindingPattern(node.name); } - function walkUpBindingElementsAndPatterns(node: Node): Node { - while (node && (node.kind === SyntaxKind.BindingElement || isBindingPattern(node))) { - node = node.parent; + export function walkUpBindingElementsAndPatterns(binding: BindingElement): VariableDeclaration | ParameterDeclaration { + let node = binding.parent; + while (isBindingElement(node.parent)) { + node = node.parent.parent; } - - return node; + return node.parent; } - export function getCombinedModifierFlags(node: Node): ModifierFlags { - node = walkUpBindingElementsAndPatterns(node); - let flags = getModifierFlags(node); + function getCombinedFlags(node: Node, getFlags: (n: Node) => number): number { + if (isBindingElement(node)) { + node = walkUpBindingElementsAndPatterns(node); + } + let flags = getFlags(node); if (node.kind === SyntaxKind.VariableDeclaration) { node = node.parent; } - if (node && node.kind === SyntaxKind.VariableDeclarationList) { - flags |= getModifierFlags(node); + flags |= getFlags(node); node = node.parent; } - if (node && node.kind === SyntaxKind.VariableStatement) { - flags |= getModifierFlags(node); + flags |= getFlags(node); } - return flags; } + export function getCombinedModifierFlags(node: Declaration): ModifierFlags { + return getCombinedFlags(node, getModifierFlags); + } + // Returns the node flags for this node and all relevant parent nodes. This is done so that // nodes like variable declarations and binding elements can returned a view of their flags // that includes the modifiers from their container. i.e. flags like export/declare aren't @@ -4640,23 +4643,7 @@ namespace ts { // list. By calling this function, all those flags are combined so that the client can treat // the node as if it actually had those flags. export function getCombinedNodeFlags(node: Node): NodeFlags { - node = walkUpBindingElementsAndPatterns(node); - - let flags = node.flags; - if (node.kind === SyntaxKind.VariableDeclaration) { - node = node.parent; - } - - if (node && node.kind === SyntaxKind.VariableDeclarationList) { - flags |= node.flags; - node = node.parent; - } - - if (node && node.kind === SyntaxKind.VariableStatement) { - flags |= node.flags; - } - - return flags; + return getCombinedFlags(node, n => n.flags); } /** diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 33f77758abd..300a1a0a2e0 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1044,7 +1044,7 @@ namespace ts { } export function getNodeModifiers(node: Node): string { - const flags = getCombinedModifierFlags(node); + const flags = isDeclaration(node) ? getCombinedModifierFlags(node) : ModifierFlags.None; const result: string[] = []; if (flags & ModifierFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index ad3a2ea1e9e..48ac4d9f979 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -6677,7 +6677,8 @@ declare namespace ts { function isParameterPropertyDeclaration(node: Node): node is ParameterPropertyDeclaration; function isEmptyBindingPattern(node: BindingName): node is BindingPattern; function isEmptyBindingElement(node: BindingElement): boolean; - function getCombinedModifierFlags(node: Node): ModifierFlags; + function walkUpBindingElementsAndPatterns(binding: BindingElement): VariableDeclaration | ParameterDeclaration; + function getCombinedModifierFlags(node: Declaration): ModifierFlags; function getCombinedNodeFlags(node: Node): NodeFlags; /** * Checks to see if the locale is in the appropriate format, diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 723b0099499..f5ace8e5b02 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3175,7 +3175,8 @@ declare namespace ts { function isParameterPropertyDeclaration(node: Node): node is ParameterPropertyDeclaration; function isEmptyBindingPattern(node: BindingName): node is BindingPattern; function isEmptyBindingElement(node: BindingElement): boolean; - function getCombinedModifierFlags(node: Node): ModifierFlags; + function walkUpBindingElementsAndPatterns(binding: BindingElement): VariableDeclaration | ParameterDeclaration; + function getCombinedModifierFlags(node: Declaration): ModifierFlags; function getCombinedNodeFlags(node: Node): NodeFlags; /** * Checks to see if the locale is in the appropriate format, diff --git a/tests/baselines/reference/contextuallyTypedBindingInitializerNegative.errors.txt b/tests/baselines/reference/contextuallyTypedBindingInitializerNegative.errors.txt new file mode 100644 index 00000000000..447ccec5ddf --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedBindingInitializerNegative.errors.txt @@ -0,0 +1,67 @@ +tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(4,20): error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(5,23): error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(6,25): error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(11,23): error TS2322: Type '{ show: (v: number) => number; }' is not assignable to type 'Show'. + Types of property 'show' are incompatible. + Type '(v: number) => number' is not assignable to type '(x: number) => string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(16,23): error TS2322: Type '(arg: string) => number' is not assignable to type '(s: string) => string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(21,14): error TS2322: Type '[number, number]' is not assignable to type '[string, number]'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(26,14): error TS2322: Type '"baz"' is not assignable to type '"foo" | "bar"'. + + +==== tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts (7 errors) ==== + interface Show { + show: (x: number) => string; + } + function f({ show: showRename = v => v }: Show) {} + ~~~~~~~~~~ +!!! error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + function f2({ "show": showRename = v => v }: Show) {} + ~~~~~~~~~~ +!!! error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + function f3({ ["show"]: showRename = v => v }: Show) {} + ~~~~~~~~~~ +!!! error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + interface Nested { + nested: Show + } + function ff({ nested: nestedRename = { show: v => v } }: Nested) {} + ~~~~~~~~~~~~ +!!! error TS2322: Type '{ show: (v: number) => number; }' is not assignable to type 'Show'. +!!! error TS2322: Types of property 'show' are incompatible. +!!! error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + interface StringIdentity { + stringIdentity(s: string): string; + } + let { stringIdentity: id = arg => arg.length }: StringIdentity = { stringIdentity: x => x}; + ~~ +!!! error TS2322: Type '(arg: string) => number' is not assignable to type '(s: string) => string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + interface Tuples { + prop: [string, number]; + } + function g({ prop = [101, 1234] }: Tuples) {} + ~~~~ +!!! error TS2322: Type '[number, number]' is not assignable to type '[string, number]'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + interface StringUnion { + prop: "foo" | "bar"; + } + function h({ prop = "baz" }: StringUnion) {} + ~~~~ +!!! error TS2322: Type '"baz"' is not assignable to type '"foo" | "bar"'. + \ No newline at end of file diff --git a/tests/baselines/reference/contextuallyTypedBindingInitializerNegative.types b/tests/baselines/reference/contextuallyTypedBindingInitializerNegative.types index 1548e626e6d..f53d29b56a2 100644 --- a/tests/baselines/reference/contextuallyTypedBindingInitializerNegative.types +++ b/tests/baselines/reference/contextuallyTypedBindingInitializerNegative.types @@ -9,7 +9,7 @@ interface Show { function f({ show: showRename = v => v }: Show) {} >f : ({ show: showRename }: Show) => void >show : any ->showRename : ((x: number) => string) | ((v: number) => number) +>showRename : (x: number) => string >v => v : (v: number) => number >v : number >v : number @@ -17,7 +17,7 @@ function f({ show: showRename = v => v }: Show) {} function f2({ "show": showRename = v => v }: Show) {} >f2 : ({ "show": showRename }: Show) => void ->showRename : ((x: number) => string) | ((v: number) => number) +>showRename : (x: number) => string >v => v : (v: number) => number >v : number >v : number @@ -26,7 +26,7 @@ function f2({ "show": showRename = v => v }: Show) {} function f3({ ["show"]: showRename = v => v }: Show) {} >f3 : ({ ["show"]: showRename }: Show) => void >"show" : "show" ->showRename : ((x: number) => string) | ((v: number) => number) +>showRename : (x: number) => string >v => v : (v: number) => number >v : number >v : number @@ -42,7 +42,7 @@ interface Nested { function ff({ nested: nestedRename = { show: v => v } }: Nested) {} >ff : ({ nested: nestedRename }: Nested) => void >nested : any ->nestedRename : Show | { show: (v: number) => number; } +>nestedRename : Show >{ show: v => v } : { show: (v: number) => number; } >show : (v: number) => number >v => v : (v: number) => number @@ -59,7 +59,7 @@ interface StringIdentity { } let { stringIdentity: id = arg => arg.length }: StringIdentity = { stringIdentity: x => x}; >stringIdentity : any ->id : ((s: string) => string) | ((arg: string) => number) +>id : (s: string) => string >arg => arg.length : (arg: string) => number >arg : string >arg.length : number @@ -80,7 +80,7 @@ interface Tuples { } function g({ prop = [101, 1234] }: Tuples) {} >g : ({ prop }: Tuples) => void ->prop : [string, number] | [number, number] +>prop : [string, number] >[101, 1234] : [number, number] >101 : 101 >1234 : 1234 @@ -94,7 +94,7 @@ interface StringUnion { } function h({ prop = "baz" }: StringUnion) {} >h : ({ prop }: StringUnion) => void ->prop : "foo" | "bar" | "baz" +>prop : "foo" | "bar" >"baz" : "baz" >StringUnion : StringUnion diff --git a/tests/baselines/reference/destructuringParameterDeclaration8.errors.txt b/tests/baselines/reference/destructuringParameterDeclaration8.errors.txt new file mode 100644 index 00000000000..0b333efe901 --- /dev/null +++ b/tests/baselines/reference/destructuringParameterDeclaration8.errors.txt @@ -0,0 +1,42 @@ +tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8.ts(4,5): error TS2322: Type '"z"' is not assignable to type '"x" | "y"'. +tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8.ts(5,15): error TS2322: Type '"c"' is not assignable to type '"a" | "b"'. +tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8.ts(17,6): error TS2345: Argument of type '{ method: "z"; nested: { p: "b"; }; }' is not assignable to parameter of type '{ method?: "x" | "y"; nested?: { p: "a" | "b"; }; }'. + Types of property 'method' are incompatible. + Type '"z"' is not assignable to type '"x" | "y"'. +tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8.ts(18,6): error TS2345: Argument of type '{ method: "one"; nested: { p: "a"; }; }' is not assignable to parameter of type '{ method?: "x" | "y"; nested?: { p: "a" | "b"; }; }'. + Types of property 'method' are incompatible. + Type '"one"' is not assignable to type '"x" | "y"'. + + +==== tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8.ts (4 errors) ==== + // explicit type annotation should cause `method` to have type 'x' | 'y' + // both inside and outside `test`. + function test({ + method = 'z', + ~~~~~~ +!!! error TS2322: Type '"z"' is not assignable to type '"x" | "y"'. + nested: { p = 'c' } + ~ +!!! error TS2322: Type '"c"' is not assignable to type '"a" | "b"'. + }: { + method?: 'x' | 'y', + nested?: { p: 'a' | 'b' } + }) + { + method + p + } + + test({}); + test({ method: 'x', nested: { p: 'a' } }) + test({ method: 'z', nested: { p: 'b' } }) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '{ method: "z"; nested: { p: "b"; }; }' is not assignable to parameter of type '{ method?: "x" | "y"; nested?: { p: "a" | "b"; }; }'. +!!! error TS2345: Types of property 'method' are incompatible. +!!! error TS2345: Type '"z"' is not assignable to type '"x" | "y"'. + test({ method: 'one', nested: { p: 'a' } }) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '{ method: "one"; nested: { p: "a"; }; }' is not assignable to parameter of type '{ method?: "x" | "y"; nested?: { p: "a" | "b"; }; }'. +!!! error TS2345: Types of property 'method' are incompatible. +!!! error TS2345: Type '"one"' is not assignable to type '"x" | "y"'. + \ No newline at end of file diff --git a/tests/baselines/reference/destructuringParameterDeclaration8.js b/tests/baselines/reference/destructuringParameterDeclaration8.js new file mode 100644 index 00000000000..4856306ecae --- /dev/null +++ b/tests/baselines/reference/destructuringParameterDeclaration8.js @@ -0,0 +1,33 @@ +//// [destructuringParameterDeclaration8.ts] +// explicit type annotation should cause `method` to have type 'x' | 'y' +// both inside and outside `test`. +function test({ + method = 'z', + nested: { p = 'c' } +}: { + method?: 'x' | 'y', + nested?: { p: 'a' | 'b' } +}) +{ + method + p +} + +test({}); +test({ method: 'x', nested: { p: 'a' } }) +test({ method: 'z', nested: { p: 'b' } }) +test({ method: 'one', nested: { p: 'a' } }) + + +//// [destructuringParameterDeclaration8.js] +// explicit type annotation should cause `method` to have type 'x' | 'y' +// both inside and outside `test`. +function test(_a) { + var _b = _a.method, method = _b === void 0 ? 'z' : _b, _c = _a.nested.p, p = _c === void 0 ? 'c' : _c; + method; + p; +} +test({}); +test({ method: 'x', nested: { p: 'a' } }); +test({ method: 'z', nested: { p: 'b' } }); +test({ method: 'one', nested: { p: 'a' } }); diff --git a/tests/baselines/reference/destructuringParameterDeclaration8.symbols b/tests/baselines/reference/destructuringParameterDeclaration8.symbols new file mode 100644 index 00000000000..f65e200fdac --- /dev/null +++ b/tests/baselines/reference/destructuringParameterDeclaration8.symbols @@ -0,0 +1,51 @@ +=== tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8.ts === +// explicit type annotation should cause `method` to have type 'x' | 'y' +// both inside and outside `test`. +function test({ +>test : Symbol(test, Decl(destructuringParameterDeclaration8.ts, 0, 0)) + + method = 'z', +>method : Symbol(method, Decl(destructuringParameterDeclaration8.ts, 2, 15)) + + nested: { p = 'c' } +>nested : Symbol(nested, Decl(destructuringParameterDeclaration8.ts, 6, 23)) +>p : Symbol(p, Decl(destructuringParameterDeclaration8.ts, 4, 13)) + +}: { + method?: 'x' | 'y', +>method : Symbol(method, Decl(destructuringParameterDeclaration8.ts, 5, 4)) + + nested?: { p: 'a' | 'b' } +>nested : Symbol(nested, Decl(destructuringParameterDeclaration8.ts, 6, 23)) +>p : Symbol(p, Decl(destructuringParameterDeclaration8.ts, 7, 14)) + +}) +{ + method +>method : Symbol(method, Decl(destructuringParameterDeclaration8.ts, 2, 15)) + + p +>p : Symbol(p, Decl(destructuringParameterDeclaration8.ts, 4, 13)) +} + +test({}); +>test : Symbol(test, Decl(destructuringParameterDeclaration8.ts, 0, 0)) + +test({ method: 'x', nested: { p: 'a' } }) +>test : Symbol(test, Decl(destructuringParameterDeclaration8.ts, 0, 0)) +>method : Symbol(method, Decl(destructuringParameterDeclaration8.ts, 15, 6)) +>nested : Symbol(nested, Decl(destructuringParameterDeclaration8.ts, 15, 19)) +>p : Symbol(p, Decl(destructuringParameterDeclaration8.ts, 15, 29)) + +test({ method: 'z', nested: { p: 'b' } }) +>test : Symbol(test, Decl(destructuringParameterDeclaration8.ts, 0, 0)) +>method : Symbol(method, Decl(destructuringParameterDeclaration8.ts, 16, 6)) +>nested : Symbol(nested, Decl(destructuringParameterDeclaration8.ts, 16, 19)) +>p : Symbol(p, Decl(destructuringParameterDeclaration8.ts, 16, 29)) + +test({ method: 'one', nested: { p: 'a' } }) +>test : Symbol(test, Decl(destructuringParameterDeclaration8.ts, 0, 0)) +>method : Symbol(method, Decl(destructuringParameterDeclaration8.ts, 17, 6)) +>nested : Symbol(nested, Decl(destructuringParameterDeclaration8.ts, 17, 21)) +>p : Symbol(p, Decl(destructuringParameterDeclaration8.ts, 17, 31)) + diff --git a/tests/baselines/reference/destructuringParameterDeclaration8.types b/tests/baselines/reference/destructuringParameterDeclaration8.types new file mode 100644 index 00000000000..6ca691fcff1 --- /dev/null +++ b/tests/baselines/reference/destructuringParameterDeclaration8.types @@ -0,0 +1,70 @@ +=== tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8.ts === +// explicit type annotation should cause `method` to have type 'x' | 'y' +// both inside and outside `test`. +function test({ +>test : ({ method, nested: { p } }: { method?: "x" | "y"; nested?: { p: "a" | "b"; }; }) => void + + method = 'z', +>method : "x" | "y" +>'z' : "z" + + nested: { p = 'c' } +>nested : any +>p : "a" | "b" +>'c' : "c" + +}: { + method?: 'x' | 'y', +>method : "x" | "y" + + nested?: { p: 'a' | 'b' } +>nested : { p: "a" | "b"; } +>p : "a" | "b" + +}) +{ + method +>method : "x" | "y" + + p +>p : "a" | "b" +} + +test({}); +>test({}) : void +>test : ({ method, nested: { p } }: { method?: "x" | "y"; nested?: { p: "a" | "b"; }; }) => void +>{} : {} + +test({ method: 'x', nested: { p: 'a' } }) +>test({ method: 'x', nested: { p: 'a' } }) : void +>test : ({ method, nested: { p } }: { method?: "x" | "y"; nested?: { p: "a" | "b"; }; }) => void +>{ method: 'x', nested: { p: 'a' } } : { method: "x"; nested: { p: "a"; }; } +>method : "x" +>'x' : "x" +>nested : { p: "a"; } +>{ p: 'a' } : { p: "a"; } +>p : "a" +>'a' : "a" + +test({ method: 'z', nested: { p: 'b' } }) +>test({ method: 'z', nested: { p: 'b' } }) : void +>test : ({ method, nested: { p } }: { method?: "x" | "y"; nested?: { p: "a" | "b"; }; }) => void +>{ method: 'z', nested: { p: 'b' } } : { method: string; nested: { p: string; }; } +>method : string +>'z' : "z" +>nested : { p: string; } +>{ p: 'b' } : { p: string; } +>p : string +>'b' : "b" + +test({ method: 'one', nested: { p: 'a' } }) +>test({ method: 'one', nested: { p: 'a' } }) : void +>test : ({ method, nested: { p } }: { method?: "x" | "y"; nested?: { p: "a" | "b"; }; }) => void +>{ method: 'one', nested: { p: 'a' } } : { method: string; nested: { p: string; }; } +>method : string +>'one' : "one" +>nested : { p: string; } +>{ p: 'a' } : { p: string; } +>p : string +>'a' : "a" + diff --git a/tests/baselines/reference/destructuringVariableDeclaration2.errors.txt b/tests/baselines/reference/destructuringVariableDeclaration2.errors.txt index fe8255ca556..0b856d8d1f7 100644 --- a/tests/baselines/reference/destructuringVariableDeclaration2.errors.txt +++ b/tests/baselines/reference/destructuringVariableDeclaration2.errors.txt @@ -5,9 +5,11 @@ tests/cases/conformance/es6/destructuring/destructuringVariableDeclaration2.ts(4 Type '[[boolean]]' is not assignable to type '[[string]]'. Type '[boolean]' is not assignable to type '[string]'. Type 'boolean' is not assignable to type 'string'. +tests/cases/conformance/es6/destructuring/destructuringVariableDeclaration2.ts(19,10): error TS2322: Type 'string[]' is not assignable to type 'number[]'. + Type 'string' is not assignable to type 'number'. -==== tests/cases/conformance/es6/destructuring/destructuringVariableDeclaration2.ts (2 errors) ==== +==== tests/cases/conformance/es6/destructuring/destructuringVariableDeclaration2.ts (3 errors) ==== // The type T associated with a destructuring variable declaration is determined as follows: // If the declaration includes a type annotation, T is that type. var {a1, a2}: { a1: number, a2: string } = { a1: true, a2: 1 } // Error @@ -35,4 +37,7 @@ tests/cases/conformance/es6/destructuring/destructuringVariableDeclaration2.ts(4 // When a destructuring variable declaration, binding property, or binding element specifies // an initializer expression, the type of the initializer expression is required to be assignable // to the widened form of the type associated with the destructuring variable declaration, binding property, or binding element. - var {d: {d1 = ["string", null]}}: { d: { d1: number[] } } = { d: { d1: [1, 2] } }; // Error \ No newline at end of file + var {d: {d1 = ["string", null]}}: { d: { d1: number[] } } = { d: { d1: [1, 2] } }; // Error + ~~ +!!! error TS2322: Type 'string[]' is not assignable to type 'number[]'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. \ No newline at end of file diff --git a/tests/baselines/reference/destructuringVariableDeclaration2.types b/tests/baselines/reference/destructuringVariableDeclaration2.types index 8af7ddb7628..43b83a4d74f 100644 --- a/tests/baselines/reference/destructuringVariableDeclaration2.types +++ b/tests/baselines/reference/destructuringVariableDeclaration2.types @@ -74,7 +74,7 @@ var [c1, c2, { c3: c4, c5 }, , ...c6] = [1, 2, { c3: 4, c5: 0 }]; // Error // to the widened form of the type associated with the destructuring variable declaration, binding property, or binding element. var {d: {d1 = ["string", null]}}: { d: { d1: number[] } } = { d: { d1: [1, 2] } }; // Error >d : any ->d1 : string[] | number[] +>d1 : number[] >["string", null] : string[] >"string" : "string" >null : null diff --git a/tests/baselines/reference/optionalParameterInDestructuringWithInitializer.errors.txt b/tests/baselines/reference/optionalParameterInDestructuringWithInitializer.errors.txt index b2fea589cb1..45bcdacb149 100644 --- a/tests/baselines/reference/optionalParameterInDestructuringWithInitializer.errors.txt +++ b/tests/baselines/reference/optionalParameterInDestructuringWithInitializer.errors.txt @@ -8,8 +8,7 @@ tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts(31,8): e Type 'undefined' is not assignable to type 'number'. tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts(45,10): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'. Type 'undefined' is not assignable to type 'number'. -tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts(53,11): error TS2345: Argument of type 'number | null' is not assignable to parameter of type 'number | undefined'. - Type 'null' is not assignable to type 'number | undefined'. +tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts(52,24): error TS2322: Type 'null' is not assignable to type 'number'. ==== tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts (6 errors) ==== @@ -80,10 +79,9 @@ tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts(53,11): performFoo(); function performFoo2({ bar = null }: Foo = {}) { + ~~~ +!!! error TS2322: Type 'null' is not assignable to type 'number'. useBar2(bar); - ~~~ -!!! error TS2345: Argument of type 'number | null' is not assignable to parameter of type 'number | undefined'. -!!! error TS2345: Type 'null' is not assignable to type 'number | undefined'. } declare function useBar2(bar: number | undefined): void; diff --git a/tests/baselines/reference/optionalParameterInDestructuringWithInitializer.types b/tests/baselines/reference/optionalParameterInDestructuringWithInitializer.types index 26110e71051..ee1c45b9c7e 100644 --- a/tests/baselines/reference/optionalParameterInDestructuringWithInitializer.types +++ b/tests/baselines/reference/optionalParameterInDestructuringWithInitializer.types @@ -225,7 +225,7 @@ performFoo(); function performFoo2({ bar = null }: Foo = {}) { >performFoo2 : ({ bar }?: Foo) => void ->bar : number | null +>bar : number >null : null >Foo : Foo >{} : {} @@ -233,7 +233,7 @@ function performFoo2({ bar = null }: Foo = {}) { useBar2(bar); >useBar2(bar) : void >useBar2 : (bar: number | undefined) => void ->bar : number | null +>bar : number } declare function useBar2(bar: number | undefined): void; diff --git a/tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8.ts b/tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8.ts new file mode 100644 index 00000000000..f0cf17c0853 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8.ts @@ -0,0 +1,18 @@ +// explicit type annotation should cause `method` to have type 'x' | 'y' +// both inside and outside `test`. +function test({ + method = 'z', + nested: { p = 'c' } +}: { + method?: 'x' | 'y', + nested?: { p: 'a' | 'b' } +}) +{ + method + p +} + +test({}); +test({ method: 'x', nested: { p: 'a' } }) +test({ method: 'z', nested: { p: 'b' } }) +test({ method: 'one', nested: { p: 'a' } }) diff --git a/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter b/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter index 40bdb4eadab..6b9706810b5 160000 --- a/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter +++ b/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter @@ -1 +1 @@ -Subproject commit 40bdb4eadabc9fbed7d83e3f26817a931c0763b6 +Subproject commit 6b9706810b55af326a93b9aa59cb17815a30bb32