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
This commit is contained in:
Nathan Shively-Sanders 2018-06-28 10:41:38 -07:00 committed by GitHub
parent 950593b669
commit 5c2eeb20b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 328 additions and 55 deletions

View File

@ -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

View File

@ -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);
}
/**

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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"'.

View File

@ -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

View File

@ -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"'.

View File

@ -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' } });

View File

@ -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))

View File

@ -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"

View File

@ -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
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'.

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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' } })

@ -1 +1 @@
Subproject commit 40bdb4eadabc9fbed7d83e3f26817a931c0763b6
Subproject commit 6b9706810b55af326a93b9aa59cb17815a30bb32