Skip to content

Commit 71b16ea

Browse files
authored
Treat contextually typed functions in JS files as typed (#56907)
1 parent eb25b58 commit 71b16ea

6 files changed

+397
-1
lines changed

src/compiler/checker.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -15504,7 +15504,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1550415504
isInJSFile(declaration) &&
1550515505
isValueSignatureDeclaration(declaration) &&
1550615506
!hasJSDocParameterTags(declaration) &&
15507-
!getJSDocType(declaration);
15507+
!getJSDocType(declaration) &&
15508+
!getContextualSignatureForFunctionLikeDeclaration(declaration);
1550815509
if (isUntypedSignatureInJSFile) {
1550915510
flags |= SignatureFlags.IsUntypedSignatureInJSFile;
1551015511
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/a.js(9,20): error TS2322: Type 'number' is not assignable to type 'string'.
2+
/a.js(28,5): error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'.
3+
Types of parameters 'b' and 'args' are incompatible.
4+
Type 'number' is not assignable to type 'string'.
5+
/a.js(42,21): error TS7006: Parameter 'uuid' implicitly has an 'any' type.
6+
7+
8+
==== /a.js (3 errors) ====
9+
/** @satisfies {(uuid: string) => void} */
10+
export const fn1 = uuid => {};
11+
12+
/** @typedef {Parameters<typeof fn1>} Foo */
13+
14+
/** @type Foo */
15+
export const v1 = ['abc'];
16+
/** @type Foo */
17+
export const v2 = [123]; // error
18+
~~~
19+
!!! error TS2322: Type 'number' is not assignable to type 'string'.
20+
21+
/** @satisfies {(a: string, ...args: never) => void} */
22+
export const fn2 = (a, b) => {};
23+
24+
/**
25+
* @satisfies {(a: string, ...args: never) => void}
26+
* @param {string} a
27+
*/
28+
export const fn3 = (a, b) => {};
29+
30+
/**
31+
* @satisfies {(a: string, ...args: never) => void}
32+
* @param {string} a
33+
* @param {number} b
34+
*/
35+
export const fn4 = (a, b) => {};
36+
37+
/**
38+
* @satisfies {(a: string, ...args: number[]) => void}
39+
~~~~~~~~~
40+
!!! error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'.
41+
!!! error TS1360: Types of parameters 'b' and 'args' are incompatible.
42+
!!! error TS1360: Type 'number' is not assignable to type 'string'.
43+
* @param {string} a
44+
* @param {string} b
45+
*/
46+
export const fn5 = (a, b) => {};
47+
48+
/**
49+
* @satisfies {(a: string, ...args: number[]) => void}
50+
* @param {string} a
51+
* @param {string | number} b
52+
*/
53+
export const fn6 = (a, b) => {};
54+
55+
/** @satisfies {(uuid: string) => void} */
56+
export function fn7(uuid) {}
57+
~~~~
58+
!!! error TS7006: Parameter 'uuid' implicitly has an 'any' type.
59+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//// [tests/cases/conformance/jsdoc/checkJsdocSatisfiesTag15.ts] ////
2+
3+
//// [a.js]
4+
/** @satisfies {(uuid: string) => void} */
5+
export const fn1 = uuid => {};
6+
7+
/** @typedef {Parameters<typeof fn1>} Foo */
8+
9+
/** @type Foo */
10+
export const v1 = ['abc'];
11+
/** @type Foo */
12+
export const v2 = [123]; // error
13+
14+
/** @satisfies {(a: string, ...args: never) => void} */
15+
export const fn2 = (a, b) => {};
16+
17+
/**
18+
* @satisfies {(a: string, ...args: never) => void}
19+
* @param {string} a
20+
*/
21+
export const fn3 = (a, b) => {};
22+
23+
/**
24+
* @satisfies {(a: string, ...args: never) => void}
25+
* @param {string} a
26+
* @param {number} b
27+
*/
28+
export const fn4 = (a, b) => {};
29+
30+
/**
31+
* @satisfies {(a: string, ...args: number[]) => void}
32+
* @param {string} a
33+
* @param {string} b
34+
*/
35+
export const fn5 = (a, b) => {};
36+
37+
/**
38+
* @satisfies {(a: string, ...args: number[]) => void}
39+
* @param {string} a
40+
* @param {string | number} b
41+
*/
42+
export const fn6 = (a, b) => {};
43+
44+
/** @satisfies {(uuid: string) => void} */
45+
export function fn7(uuid) {}
46+
47+
48+
//// [a.js]
49+
"use strict";
50+
Object.defineProperty(exports, "__esModule", { value: true });
51+
exports.fn6 = exports.fn5 = exports.fn4 = exports.fn3 = exports.fn2 = exports.v2 = exports.v1 = exports.fn1 = void 0;
52+
exports.fn7 = fn7;
53+
/** @satisfies {(uuid: string) => void} */
54+
var fn1 = function (uuid) { };
55+
exports.fn1 = fn1;
56+
/** @typedef {Parameters<typeof fn1>} Foo */
57+
/** @type Foo */
58+
exports.v1 = ['abc'];
59+
/** @type Foo */
60+
exports.v2 = [123]; // error
61+
/** @satisfies {(a: string, ...args: never) => void} */
62+
var fn2 = function (a, b) { };
63+
exports.fn2 = fn2;
64+
/**
65+
* @satisfies {(a: string, ...args: never) => void}
66+
* @param {string} a
67+
*/
68+
var fn3 = function (a, b) { };
69+
exports.fn3 = fn3;
70+
/**
71+
* @satisfies {(a: string, ...args: never) => void}
72+
* @param {string} a
73+
* @param {number} b
74+
*/
75+
var fn4 = function (a, b) { };
76+
exports.fn4 = fn4;
77+
/**
78+
* @satisfies {(a: string, ...args: number[]) => void}
79+
* @param {string} a
80+
* @param {string} b
81+
*/
82+
var fn5 = function (a, b) { };
83+
exports.fn5 = fn5;
84+
/**
85+
* @satisfies {(a: string, ...args: number[]) => void}
86+
* @param {string} a
87+
* @param {string | number} b
88+
*/
89+
var fn6 = function (a, b) { };
90+
exports.fn6 = fn6;
91+
/** @satisfies {(uuid: string) => void} */
92+
function fn7(uuid) { }
93+
94+
95+
//// [a.d.ts]
96+
/** @satisfies {(uuid: string) => void} */
97+
export function fn7(uuid: any): void;
98+
export function fn1(uuid: string): void;
99+
/** @typedef {Parameters<typeof fn1>} Foo */
100+
/** @type Foo */
101+
export const v1: Foo;
102+
/** @type Foo */
103+
export const v2: Foo;
104+
export function fn2(a: string, b: never): void;
105+
export function fn3(a: string, b: never): void;
106+
export function fn4(a: string, b: number): void;
107+
export function fn5(a: string, b: string): void;
108+
export function fn6(a: string, b: string | number): void;
109+
export type Foo = Parameters<typeof fn1>;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//// [tests/cases/conformance/jsdoc/checkJsdocSatisfiesTag15.ts] ////
2+
3+
=== /a.js ===
4+
/** @satisfies {(uuid: string) => void} */
5+
export const fn1 = uuid => {};
6+
>fn1 : Symbol(fn1, Decl(a.js, 1, 12))
7+
>uuid : Symbol(uuid, Decl(a.js, 1, 18))
8+
9+
/** @typedef {Parameters<typeof fn1>} Foo */
10+
11+
/** @type Foo */
12+
export const v1 = ['abc'];
13+
>v1 : Symbol(v1, Decl(a.js, 6, 12))
14+
15+
/** @type Foo */
16+
export const v2 = [123]; // error
17+
>v2 : Symbol(v2, Decl(a.js, 8, 12))
18+
19+
/** @satisfies {(a: string, ...args: never) => void} */
20+
export const fn2 = (a, b) => {};
21+
>fn2 : Symbol(fn2, Decl(a.js, 11, 12))
22+
>a : Symbol(a, Decl(a.js, 11, 20))
23+
>b : Symbol(b, Decl(a.js, 11, 22))
24+
25+
/**
26+
* @satisfies {(a: string, ...args: never) => void}
27+
* @param {string} a
28+
*/
29+
export const fn3 = (a, b) => {};
30+
>fn3 : Symbol(fn3, Decl(a.js, 17, 12))
31+
>a : Symbol(a, Decl(a.js, 17, 20))
32+
>b : Symbol(b, Decl(a.js, 17, 22))
33+
34+
/**
35+
* @satisfies {(a: string, ...args: never) => void}
36+
* @param {string} a
37+
* @param {number} b
38+
*/
39+
export const fn4 = (a, b) => {};
40+
>fn4 : Symbol(fn4, Decl(a.js, 24, 12))
41+
>a : Symbol(a, Decl(a.js, 24, 20))
42+
>b : Symbol(b, Decl(a.js, 24, 22))
43+
44+
/**
45+
* @satisfies {(a: string, ...args: number[]) => void}
46+
* @param {string} a
47+
* @param {string} b
48+
*/
49+
export const fn5 = (a, b) => {};
50+
>fn5 : Symbol(fn5, Decl(a.js, 31, 12))
51+
>a : Symbol(a, Decl(a.js, 31, 20))
52+
>b : Symbol(b, Decl(a.js, 31, 22))
53+
54+
/**
55+
* @satisfies {(a: string, ...args: number[]) => void}
56+
* @param {string} a
57+
* @param {string | number} b
58+
*/
59+
export const fn6 = (a, b) => {};
60+
>fn6 : Symbol(fn6, Decl(a.js, 38, 12))
61+
>a : Symbol(a, Decl(a.js, 38, 20))
62+
>b : Symbol(b, Decl(a.js, 38, 22))
63+
64+
/** @satisfies {(uuid: string) => void} */
65+
export function fn7(uuid) {}
66+
>fn7 : Symbol(fn7, Decl(a.js, 38, 32))
67+
>uuid : Symbol(uuid, Decl(a.js, 41, 20))
68+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//// [tests/cases/conformance/jsdoc/checkJsdocSatisfiesTag15.ts] ////
2+
3+
=== /a.js ===
4+
/** @satisfies {(uuid: string) => void} */
5+
export const fn1 = uuid => {};
6+
>fn1 : (uuid: string) => void
7+
> : ^ ^^^^^^^^^^^^^^^^^
8+
>uuid => {} : (uuid: string) => void
9+
> : ^ ^^^^^^^^^^^^^^^^^
10+
>uuid : string
11+
> : ^^^^^^
12+
13+
/** @typedef {Parameters<typeof fn1>} Foo */
14+
15+
/** @type Foo */
16+
export const v1 = ['abc'];
17+
>v1 : [uuid: string]
18+
> : ^^^^^^^^^^^^^^
19+
>['abc'] : [string]
20+
> : ^^^^^^^^
21+
>'abc' : "abc"
22+
> : ^^^^^
23+
24+
/** @type Foo */
25+
export const v2 = [123]; // error
26+
>v2 : [uuid: string]
27+
> : ^^^^^^^^^^^^^^
28+
>[123] : [number]
29+
> : ^^^^^^^^
30+
>123 : 123
31+
> : ^^^
32+
33+
/** @satisfies {(a: string, ...args: never) => void} */
34+
export const fn2 = (a, b) => {};
35+
>fn2 : (a: string, b: never) => void
36+
> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^
37+
>(a, b) => {} : (a: string, b: never) => void
38+
> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^
39+
>a : string
40+
> : ^^^^^^
41+
>b : never
42+
> : ^^^^^
43+
44+
/**
45+
* @satisfies {(a: string, ...args: never) => void}
46+
* @param {string} a
47+
*/
48+
export const fn3 = (a, b) => {};
49+
>fn3 : (a: string, b: never) => void
50+
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^
51+
>(a, b) => {} : (a: string, b: never) => void
52+
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^
53+
>a : string
54+
> : ^^^^^^
55+
>b : never
56+
> : ^^^^^
57+
58+
/**
59+
* @satisfies {(a: string, ...args: never) => void}
60+
* @param {string} a
61+
* @param {number} b
62+
*/
63+
export const fn4 = (a, b) => {};
64+
>fn4 : (a: string, b: number) => void
65+
> : ^ ^^ ^^ ^^ ^^^^^^^^^
66+
>(a, b) => {} : (a: string, b: number) => void
67+
> : ^ ^^ ^^ ^^ ^^^^^^^^^
68+
>a : string
69+
> : ^^^^^^
70+
>b : number
71+
> : ^^^^^^
72+
73+
/**
74+
* @satisfies {(a: string, ...args: number[]) => void}
75+
* @param {string} a
76+
* @param {string} b
77+
*/
78+
export const fn5 = (a, b) => {};
79+
>fn5 : (a: string, b: string) => void
80+
> : ^ ^^ ^^ ^^ ^^^^^^^^^
81+
>(a, b) => {} : (a: string, b: string) => void
82+
> : ^ ^^ ^^ ^^ ^^^^^^^^^
83+
>a : string
84+
> : ^^^^^^
85+
>b : string
86+
> : ^^^^^^
87+
88+
/**
89+
* @satisfies {(a: string, ...args: number[]) => void}
90+
* @param {string} a
91+
* @param {string | number} b
92+
*/
93+
export const fn6 = (a, b) => {};
94+
>fn6 : (a: string, b: string | number) => void
95+
> : ^ ^^ ^^ ^^ ^^^^^^^^^
96+
>(a, b) => {} : (a: string, b: string | number) => void
97+
> : ^ ^^ ^^ ^^ ^^^^^^^^^
98+
>a : string
99+
> : ^^^^^^
100+
>b : string | number
101+
> : ^^^^^^^^^^^^^^^
102+
103+
/** @satisfies {(uuid: string) => void} */
104+
export function fn7(uuid) {}
105+
>fn7 : (uuid: any) => void
106+
> : ^ ^^^^^^^^^^^^^^
107+
>uuid : any
108+
> : ^^^
109+

0 commit comments

Comments
 (0)