Filter undefined only in binding patterns in params (#38116)

initialiser. But this is only correct when the initialiser is for a
parameter. For example:

```ts
declare let x: { s: string } | undefined;
const { s } = x;
```

This PR removes undefined from the type of a binding pattern only when
the binding pattern's parent is a parameter. This fixes the regression
from 3.8. However, it's still not the ideal fix; we should be able to
use control flow to solve this problem. Consider:

```ts
const { s }: { s: string } | undefined = { s: 'hi' }
declare function f({ s }: { s: string } | undefined = { s: 'hi' }): void
```

Neither line should have an error, but the first does in 3.8 and after
this change.
This commit is contained in:
Nathan Shively-Sanders 2020-04-22 09:56:32 -07:00 committed by GitHub
parent d2016912b5
commit f248567dab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 41 additions and 3 deletions

View file

@ -7306,7 +7306,7 @@ namespace ts {
parentType = getNonNullableType(parentType);
}
// Filter `undefined` from the type we check against if the parent has an initializer (which handles the `undefined` case implicitly)
else if (strictNullChecks && pattern.parent.initializer) {
else if (strictNullChecks && pattern.parent.initializer && isParameter(pattern.parent)) {
parentType = getTypeWithFacts(parentType, TypeFacts.NEUndefined);
}

View file

@ -0,0 +1,14 @@
tests/cases/compiler/contextualTypeForInitalizedVariablesFiltersUndefined.ts(7,9): error TS2339: Property 's' does not exist on type '{ s: string; } | undefined'.
==== tests/cases/compiler/contextualTypeForInitalizedVariablesFiltersUndefined.ts (1 errors) ====
const fInferred = ({ a = 0 } = {}) => a;
// const fInferred: ({ a }?: { a?: number; }) => number
const fAnnotated: typeof fInferred = ({ a = 0 } = {}) => a;
declare var t: { s: string } | undefined;
const { s } = t;
~
!!! error TS2339: Property 's' does not exist on type '{ s: string; } | undefined'.

View file

@ -2,7 +2,11 @@
const fInferred = ({ a = 0 } = {}) => a;
// const fInferred: ({ a }?: { a?: number; }) => number
const fAnnotated: typeof fInferred = ({ a = 0 } = {}) => a;
const fAnnotated: typeof fInferred = ({ a = 0 } = {}) => a;
declare var t: { s: string } | undefined;
const { s } = t;
//// [contextualTypeForInitalizedVariablesFiltersUndefined.js]
"use strict";
@ -15,3 +19,4 @@ var fAnnotated = function (_a) {
var _b = (_a === void 0 ? {} : _a).a, a = _b === void 0 ? 0 : _b;
return a;
};
var s = t.s;

View file

@ -12,3 +12,11 @@ const fAnnotated: typeof fInferred = ({ a = 0 } = {}) => a;
>a : Symbol(a, Decl(contextualTypeForInitalizedVariablesFiltersUndefined.ts, 3, 39))
>a : Symbol(a, Decl(contextualTypeForInitalizedVariablesFiltersUndefined.ts, 3, 39))
declare var t: { s: string } | undefined;
>t : Symbol(t, Decl(contextualTypeForInitalizedVariablesFiltersUndefined.ts, 5, 11))
>s : Symbol(s, Decl(contextualTypeForInitalizedVariablesFiltersUndefined.ts, 5, 16))
const { s } = t;
>s : Symbol(s, Decl(contextualTypeForInitalizedVariablesFiltersUndefined.ts, 6, 7))
>t : Symbol(t, Decl(contextualTypeForInitalizedVariablesFiltersUndefined.ts, 5, 11))

View file

@ -18,3 +18,11 @@ const fAnnotated: typeof fInferred = ({ a = 0 } = {}) => a;
>{} : {}
>a : number
declare var t: { s: string } | undefined;
>t : { s: string; } | undefined
>s : string
const { s } = t;
>s : any
>t : { s: string; } | undefined

View file

@ -2,4 +2,7 @@
const fInferred = ({ a = 0 } = {}) => a;
// const fInferred: ({ a }?: { a?: number; }) => number
const fAnnotated: typeof fInferred = ({ a = 0 } = {}) => a;
const fAnnotated: typeof fInferred = ({ a = 0 } = {}) => a;
declare var t: { s: string } | undefined;
const { s } = t;