Skip to content

Issue implicit any in JS files on widened inferred types from initializers in binding patterns #1064

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -15884,6 +15884,21 @@ func (c *Checker) padTupleType(t *Type, pattern *ast.Node) *Type {
}

func (c *Checker) widenTypeInferredFromInitializer(declaration *ast.Node, t *Type) *Type {
widened := c.getWidenedLiteralTypeForInitializer(declaration, t)
if ast.IsInJSFile(declaration) {
if c.isEmptyLiteralType(widened) {
c.reportImplicitAny(declaration, c.anyType, WideningKindNormal)
return c.anyType
}
if c.isEmptyArrayLiteralType(widened) {
c.reportImplicitAny(declaration, c.anyArrayType, WideningKindNormal)
return c.anyArrayType
}
}
return widened
}

func (c *Checker) getWidenedLiteralTypeForInitializer(declaration *ast.Node, t *Type) *Type {
if c.getCombinedNodeFlagsCached(declaration)&ast.NodeFlagsConstant != 0 || isDeclarationReadonly(declaration) {
return t
}
Expand Down Expand Up @@ -17004,7 +17019,7 @@ func (c *Checker) getTypeFromBindingElement(element *ast.Node, includePatternInT
if ast.IsBindingPattern(element.Name()) {
contextualType = c.getTypeFromBindingPattern(element.Name(), true /*includePatternInType*/, false /*reportErrors*/)
}
return c.addOptionality(c.widenTypeInferredFromInitializer(element, c.checkDeclarationInitializer(element, CheckModeNormal, contextualType)))
return c.addOptionality(c.getWidenedLiteralTypeForInitializer(element, c.checkDeclarationInitializer(element, CheckModeNormal, contextualType)))
}
if ast.IsBindingPattern(element.Name()) {
return c.getTypeFromBindingPattern(element.Name(), includePatternInType, reportErrors)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
index.js(7,9): error TS7031: Binding element 'json' implicitly has an 'any[]' type.
index.js(15,9): error TS7031: Binding element 'json' implicitly has an 'any[]' type.
index.js(37,20): error TS7031: Binding element 'json' implicitly has an 'any[]' type.
index.js(42,15): error TS7031: Binding element 'json' implicitly has an 'any[]' type.


==== index.js (4 errors) ====
/**
* @param {Object} [config]
* @param {Partial<Record<'json' | 'jsonc' | 'json5', string[]>>} [config.additionalFiles]
*/
export function prepareConfig({
additionalFiles: {
json = []
~~~~
!!! error TS7031: Binding element 'json' implicitly has an 'any[]' type.
} = {}
} = {}) {
json // string[]
}

export function prepareConfigWithoutAnnotation({
additionalFiles: {
json = []
~~~~
!!! error TS7031: Binding element 'json' implicitly has an 'any[]' type.
} = {}
} = {}) {
json
}

/** @type {(param: {
additionalFiles?: Partial<Record<"json" | "jsonc" | "json5", string[]>>;
}) => void} */
export const prepareConfigWithContextualSignature = ({
additionalFiles: {
json = []
} = {}
} = {})=> {
json // string[]
}

// Additional repros from https://github.com/microsoft/TypeScript/issues/59936

/**
* @param {{ a?: { json?: string[] }}} [config]
*/
function f1({ a: { json = [] } = {} } = {}) { return json }
~~~~
!!! error TS7031: Binding element 'json' implicitly has an 'any[]' type.

/**
* @param {[[string[]?]?]} [x]
*/
function f2([[json = []] = []] = []) { return json }
~~~~
!!! error TS7031: Binding element 'json' implicitly has an 'any[]' type.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function prepareConfig({
>additionalFiles : any

json = []
>json : never[]
>json : any[]
>[] : never[]

} = {}
Expand All @@ -22,7 +22,7 @@ export function prepareConfig({
>{} : {}

json // string[]
>json : never[]
>json : any[]
}

export function prepareConfigWithoutAnnotation({
Expand All @@ -32,7 +32,7 @@ export function prepareConfigWithoutAnnotation({
>additionalFiles : any

json = []
>json : never[]
>json : any[]
>[] : never[]

} = {}
Expand All @@ -42,7 +42,7 @@ export function prepareConfigWithoutAnnotation({
>{} : {}

json
>json : never[]
>json : any[]
}

/** @type {(param: {
Expand Down Expand Up @@ -75,22 +75,22 @@ export const prepareConfigWithContextualSignature = ({
* @param {{ a?: { json?: string[] }}} [config]
*/
function f1({ a: { json = [] } = {} } = {}) { return json }
>f1 : ({ a: { json } }?: { a?: { json?: never[] | undefined; } | undefined; }) => never[]
>f1 : ({ a: { json } }?: { a?: { json?: never[] | undefined; } | undefined; }) => any[]
>a : any
>json : never[]
>json : any[]
>[] : never[]
>{} : {}
>{} : {}
>json : never[]
>json : any[]

/**
* @param {[[string[]?]?]} [x]
*/
function f2([[json = []] = []] = []) { return json }
>f2 : ([[json]]?: [([(never[] | undefined)?] | undefined)?]) => never[]
>json : never[]
>f2 : ([[json]]?: [([(never[] | undefined)?] | undefined)?]) => any[]
>json : any[]
>[] : never[]
>[] : []
>[] : []
>json : never[]
>json : any[]

Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
a.js(7,9): error TS7009: 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.
a.js(25,29): error TS7006: Parameter 'l' implicitly has an 'any[]' type.
a.js(27,5): error TS2322: Type 'undefined' is not assignable to type 'null'.
a.js(29,5): error TS2322: Type '1' is not assignable to type 'null'.
a.js(30,5): error TS2322: Type 'true' is not assignable to type 'null'.
a.js(31,5): error TS2322: Type '{}' is not assignable to type 'null'.
a.js(32,5): error TS2322: Type '"ok"' is not assignable to type 'null'.
a.js(37,5): error TS2322: Type 'string' is not assignable to type 'number'.
a.js(40,12): error TS2345: Argument of type '1' is not assignable to parameter of type 'never'.
a.js(41,12): error TS2345: Argument of type '"ok"' is not assignable to parameter of type 'never'.


==== a.js (9 errors) ====
==== a.js (8 errors) ====
function A () {
// should get any on this-assignments in constructor
this.unknown = null
Expand Down Expand Up @@ -37,6 +36,8 @@ a.js(41,12): error TS2345: Argument of type '"ok"' is not assignable to paramete

// should get any on parameter initialisers
function f(a = null, b = n, l = []) {
~~~~~~
!!! error TS7006: Parameter 'l' implicitly has an 'any[]' type.
// a should be null in strict mode
a = undefined
~
Expand Down Expand Up @@ -64,11 +65,7 @@ a.js(41,12): error TS2345: Argument of type '"ok"' is not assignable to paramete

// l should be any[]
l.push(1)
~
!!! error TS2345: Argument of type '1' is not assignable to parameter of type 'never'.
l.push('ok')
~~~~
!!! error TS2345: Argument of type '"ok"' is not assignable to parameter of type 'never'.
}

// should get any on variable initialisers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,11 @@ var n;

// should get any on parameter initialisers
function f(a = null, b = n, l = []) {
>f : (a?: null, b?: number | undefined, l?: never[]) => void
>f : (a?: null, b?: number | undefined, l?: any[]) => void
>a : null
>b : number | undefined
>n : number | undefined
>l : never[]
>l : any[]
>[] : never[]

// a should be null in strict mode
Expand Down Expand Up @@ -184,16 +184,16 @@ function f(a = null, b = n, l = []) {
// l should be any[]
l.push(1)
>l.push(1) : number
>l.push : (...items: never[]) => number
>l : never[]
>push : (...items: never[]) => number
>l.push : (...items: any[]) => number
>l : any[]
>push : (...items: any[]) => number
>1 : 1

l.push('ok')
>l.push('ok') : number
>l.push : (...items: never[]) => number
>l : never[]
>push : (...items: never[]) => number
>l.push : (...items: any[]) => number
>l : any[]
>push : (...items: any[]) => number
>'ok' : "ok"
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,53 +1,39 @@
--- old.destructuringParameterDeclaration9(strict=true).errors.txt
+++ new.destructuringParameterDeclaration9(strict=true).errors.txt
@@= skipped -0, +0 lines =@@
-index.js(15,9): error TS7031: Binding element 'json' implicitly has an 'any[]' type.
+index.js(7,9): error TS7031: Binding element 'json' implicitly has an 'any[]' type.
index.js(15,9): error TS7031: Binding element 'json' implicitly has an 'any[]' type.
-
-
-==== index.js (1 errors) ====
- /**
- * @param {Object} [config]
- * @param {Partial<Record<'json' | 'jsonc' | 'json5', string[]>>} [config.additionalFiles]
- */
- export function prepareConfig({
- additionalFiles: {
- json = []
- } = {}
- } = {}) {
- json // string[]
- }
-
- export function prepareConfigWithoutAnnotation({
- additionalFiles: {
- json = []
- ~~~~
-!!! error TS7031: Binding element 'json' implicitly has an 'any[]' type.
- } = {}
- } = {}) {
- json
- }
-
- /** @type {(param: {
- additionalFiles?: Partial<Record<"json" | "jsonc" | "json5", string[]>>;
- }) => void} */
- export const prepareConfigWithContextualSignature = ({
- additionalFiles: {
- json = []
- } = {}
- } = {})=> {
- json // string[]
- }
-
- // Additional repros from https://github.com/microsoft/TypeScript/issues/59936
-
- /**
- * @param {{ a?: { json?: string[] }}} [config]
- */
- function f1({ a: { json = [] } = {} } = {}) { return json }
-
- /**
- * @param {[[string[]?]?]} [x]
- */
- function f2([[json = []] = []] = []) { return json }
-
+<no content>
+index.js(37,20): error TS7031: Binding element 'json' implicitly has an 'any[]' type.
+index.js(42,15): error TS7031: Binding element 'json' implicitly has an 'any[]' type.
+
+
+==== index.js (4 errors) ====
/**
* @param {Object} [config]
* @param {Partial<Record<'json' | 'jsonc' | 'json5', string[]>>} [config.additionalFiles]
@@= skipped -8, +11 lines =@@
export function prepareConfig({
additionalFiles: {
json = []
+ ~~~~
+!!! error TS7031: Binding element 'json' implicitly has an 'any[]' type.
} = {}
} = {}) {
json // string[]
@@= skipped -32, +34 lines =@@
* @param {{ a?: { json?: string[] }}} [config]
*/
function f1({ a: { json = [] } = {} } = {}) { return json }
+ ~~~~
+!!! error TS7031: Binding element 'json' implicitly has an 'any[]' type.

/**
* @param {[[string[]?]?]} [x]
*/
function f2([[json = []] = []] = []) { return json }
+ ~~~~
+!!! error TS7031: Binding element 'json' implicitly has an 'any[]' type.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

json = []
->json : string[]
+>json : never[]
+>json : any[]
>[] : never[]

} = {}
Expand All @@ -21,28 +21,11 @@

json // string[]
->json : string[]
+>json : never[]
+>json : any[]
}

export function prepareConfigWithoutAnnotation({
@@= skipped -10, +10 lines =@@
>additionalFiles : any

json = []
->json : any[]
+>json : never[]
>[] : never[]

} = {}
@@= skipped -10, +10 lines =@@
>{} : {}

json
->json : any[]
+>json : never[]
}

/** @type {(param: {
@@= skipped -27, +27 lines =@@
additionalFiles?: Partial<Record<"json" | "jsonc" | "json5", string[]>>;
}) => void} */
export const prepareConfigWithContextualSignature = ({
Expand All @@ -53,31 +36,31 @@

additionalFiles: {
>additionalFiles : any
@@= skipped -33, +33 lines =@@
@@= skipped -26, +26 lines =@@
* @param {{ a?: { json?: string[] }}} [config]
*/
function f1({ a: { json = [] } = {} } = {}) { return json }
->f1 : ({ a: { json } }?: { a?: { json?: string[]; }; }) => string[]
+>f1 : ({ a: { json } }?: { a?: { json?: never[] | undefined; } | undefined; }) => never[]
+>f1 : ({ a: { json } }?: { a?: { json?: never[] | undefined; } | undefined; }) => any[]
>a : any
->json : string[]
+>json : never[]
+>json : any[]
>[] : never[]
>{} : {}
>{} : {}
->json : string[]
+>json : never[]
+>json : any[]

/**
* @param {[[string[]?]?]} [x]
*/
function f2([[json = []] = []] = []) { return json }
->f2 : ([[json]]?: [[string[]?]?]) => string[]
->json : string[]
+>f2 : ([[json]]?: [([(never[] | undefined)?] | undefined)?]) => never[]
+>json : never[]
+>f2 : ([[json]]?: [([(never[] | undefined)?] | undefined)?]) => any[]
+>json : any[]
>[] : never[]
>[] : []
>[] : []
->json : string[]
+>json : never[]
+>json : any[]
Loading