Skip to content

Commit

Permalink
Treat contextually typed functions in JS files as typed (#56907)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist authored Feb 20, 2025
1 parent eb25b58 commit 71b16ea
Show file tree
Hide file tree
Showing 6 changed files with 397 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15504,7 +15504,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
isInJSFile(declaration) &&
isValueSignatureDeclaration(declaration) &&
!hasJSDocParameterTags(declaration) &&
!getJSDocType(declaration);
!getJSDocType(declaration) &&
!getContextualSignatureForFunctionLikeDeclaration(declaration);
if (isUntypedSignatureInJSFile) {
flags |= SignatureFlags.IsUntypedSignatureInJSFile;
}
Expand Down
59 changes: 59 additions & 0 deletions tests/baselines/reference/checkJsdocSatisfiesTag15.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/a.js(9,20): error TS2322: Type 'number' is not assignable to type 'string'.
/a.js(28,5): error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'.
Types of parameters 'b' and 'args' are incompatible.
Type 'number' is not assignable to type 'string'.
/a.js(42,21): error TS7006: Parameter 'uuid' implicitly has an 'any' type.


==== /a.js (3 errors) ====
/** @satisfies {(uuid: string) => void} */
export const fn1 = uuid => {};

/** @typedef {Parameters<typeof fn1>} Foo */

/** @type Foo */
export const v1 = ['abc'];
/** @type Foo */
export const v2 = [123]; // error
~~~
!!! error TS2322: Type 'number' is not assignable to type 'string'.

/** @satisfies {(a: string, ...args: never) => void} */
export const fn2 = (a, b) => {};

/**
* @satisfies {(a: string, ...args: never) => void}
* @param {string} a
*/
export const fn3 = (a, b) => {};

/**
* @satisfies {(a: string, ...args: never) => void}
* @param {string} a
* @param {number} b
*/
export const fn4 = (a, b) => {};

/**
* @satisfies {(a: string, ...args: number[]) => void}
~~~~~~~~~
!!! error TS1360: Type '(a: string, b: string) => void' does not satisfy the expected type '(a: string, ...args: number[]) => void'.
!!! error TS1360: Types of parameters 'b' and 'args' are incompatible.
!!! error TS1360: Type 'number' is not assignable to type 'string'.
* @param {string} a
* @param {string} b
*/
export const fn5 = (a, b) => {};

/**
* @satisfies {(a: string, ...args: number[]) => void}
* @param {string} a
* @param {string | number} b
*/
export const fn6 = (a, b) => {};

/** @satisfies {(uuid: string) => void} */
export function fn7(uuid) {}
~~~~
!!! error TS7006: Parameter 'uuid' implicitly has an 'any' type.

109 changes: 109 additions & 0 deletions tests/baselines/reference/checkJsdocSatisfiesTag15.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//// [tests/cases/conformance/jsdoc/checkJsdocSatisfiesTag15.ts] ////

//// [a.js]
/** @satisfies {(uuid: string) => void} */
export const fn1 = uuid => {};

/** @typedef {Parameters<typeof fn1>} Foo */

/** @type Foo */
export const v1 = ['abc'];
/** @type Foo */
export const v2 = [123]; // error

/** @satisfies {(a: string, ...args: never) => void} */
export const fn2 = (a, b) => {};

/**
* @satisfies {(a: string, ...args: never) => void}
* @param {string} a
*/
export const fn3 = (a, b) => {};

/**
* @satisfies {(a: string, ...args: never) => void}
* @param {string} a
* @param {number} b
*/
export const fn4 = (a, b) => {};

/**
* @satisfies {(a: string, ...args: number[]) => void}
* @param {string} a
* @param {string} b
*/
export const fn5 = (a, b) => {};

/**
* @satisfies {(a: string, ...args: number[]) => void}
* @param {string} a
* @param {string | number} b
*/
export const fn6 = (a, b) => {};

/** @satisfies {(uuid: string) => void} */
export function fn7(uuid) {}


//// [a.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fn6 = exports.fn5 = exports.fn4 = exports.fn3 = exports.fn2 = exports.v2 = exports.v1 = exports.fn1 = void 0;
exports.fn7 = fn7;
/** @satisfies {(uuid: string) => void} */
var fn1 = function (uuid) { };
exports.fn1 = fn1;
/** @typedef {Parameters<typeof fn1>} Foo */
/** @type Foo */
exports.v1 = ['abc'];
/** @type Foo */
exports.v2 = [123]; // error
/** @satisfies {(a: string, ...args: never) => void} */
var fn2 = function (a, b) { };
exports.fn2 = fn2;
/**
* @satisfies {(a: string, ...args: never) => void}
* @param {string} a
*/
var fn3 = function (a, b) { };
exports.fn3 = fn3;
/**
* @satisfies {(a: string, ...args: never) => void}
* @param {string} a
* @param {number} b
*/
var fn4 = function (a, b) { };
exports.fn4 = fn4;
/**
* @satisfies {(a: string, ...args: number[]) => void}
* @param {string} a
* @param {string} b
*/
var fn5 = function (a, b) { };
exports.fn5 = fn5;
/**
* @satisfies {(a: string, ...args: number[]) => void}
* @param {string} a
* @param {string | number} b
*/
var fn6 = function (a, b) { };
exports.fn6 = fn6;
/** @satisfies {(uuid: string) => void} */
function fn7(uuid) { }


//// [a.d.ts]
/** @satisfies {(uuid: string) => void} */
export function fn7(uuid: any): void;
export function fn1(uuid: string): void;
/** @typedef {Parameters<typeof fn1>} Foo */
/** @type Foo */
export const v1: Foo;
/** @type Foo */
export const v2: Foo;
export function fn2(a: string, b: never): void;
export function fn3(a: string, b: never): void;
export function fn4(a: string, b: number): void;
export function fn5(a: string, b: string): void;
export function fn6(a: string, b: string | number): void;
export type Foo = Parameters<typeof fn1>;
68 changes: 68 additions & 0 deletions tests/baselines/reference/checkJsdocSatisfiesTag15.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//// [tests/cases/conformance/jsdoc/checkJsdocSatisfiesTag15.ts] ////

=== /a.js ===
/** @satisfies {(uuid: string) => void} */
export const fn1 = uuid => {};
>fn1 : Symbol(fn1, Decl(a.js, 1, 12))
>uuid : Symbol(uuid, Decl(a.js, 1, 18))

/** @typedef {Parameters<typeof fn1>} Foo */

/** @type Foo */
export const v1 = ['abc'];
>v1 : Symbol(v1, Decl(a.js, 6, 12))

/** @type Foo */
export const v2 = [123]; // error
>v2 : Symbol(v2, Decl(a.js, 8, 12))

/** @satisfies {(a: string, ...args: never) => void} */
export const fn2 = (a, b) => {};
>fn2 : Symbol(fn2, Decl(a.js, 11, 12))
>a : Symbol(a, Decl(a.js, 11, 20))
>b : Symbol(b, Decl(a.js, 11, 22))

/**
* @satisfies {(a: string, ...args: never) => void}
* @param {string} a
*/
export const fn3 = (a, b) => {};
>fn3 : Symbol(fn3, Decl(a.js, 17, 12))
>a : Symbol(a, Decl(a.js, 17, 20))
>b : Symbol(b, Decl(a.js, 17, 22))

/**
* @satisfies {(a: string, ...args: never) => void}
* @param {string} a
* @param {number} b
*/
export const fn4 = (a, b) => {};
>fn4 : Symbol(fn4, Decl(a.js, 24, 12))
>a : Symbol(a, Decl(a.js, 24, 20))
>b : Symbol(b, Decl(a.js, 24, 22))

/**
* @satisfies {(a: string, ...args: number[]) => void}
* @param {string} a
* @param {string} b
*/
export const fn5 = (a, b) => {};
>fn5 : Symbol(fn5, Decl(a.js, 31, 12))
>a : Symbol(a, Decl(a.js, 31, 20))
>b : Symbol(b, Decl(a.js, 31, 22))

/**
* @satisfies {(a: string, ...args: number[]) => void}
* @param {string} a
* @param {string | number} b
*/
export const fn6 = (a, b) => {};
>fn6 : Symbol(fn6, Decl(a.js, 38, 12))
>a : Symbol(a, Decl(a.js, 38, 20))
>b : Symbol(b, Decl(a.js, 38, 22))

/** @satisfies {(uuid: string) => void} */
export function fn7(uuid) {}
>fn7 : Symbol(fn7, Decl(a.js, 38, 32))
>uuid : Symbol(uuid, Decl(a.js, 41, 20))

109 changes: 109 additions & 0 deletions tests/baselines/reference/checkJsdocSatisfiesTag15.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//// [tests/cases/conformance/jsdoc/checkJsdocSatisfiesTag15.ts] ////

=== /a.js ===
/** @satisfies {(uuid: string) => void} */
export const fn1 = uuid => {};
>fn1 : (uuid: string) => void
> : ^ ^^^^^^^^^^^^^^^^^
>uuid => {} : (uuid: string) => void
> : ^ ^^^^^^^^^^^^^^^^^
>uuid : string
> : ^^^^^^

/** @typedef {Parameters<typeof fn1>} Foo */

/** @type Foo */
export const v1 = ['abc'];
>v1 : [uuid: string]
> : ^^^^^^^^^^^^^^
>['abc'] : [string]
> : ^^^^^^^^
>'abc' : "abc"
> : ^^^^^

/** @type Foo */
export const v2 = [123]; // error
>v2 : [uuid: string]
> : ^^^^^^^^^^^^^^
>[123] : [number]
> : ^^^^^^^^
>123 : 123
> : ^^^

/** @satisfies {(a: string, ...args: never) => void} */
export const fn2 = (a, b) => {};
>fn2 : (a: string, b: never) => void
> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^
>(a, b) => {} : (a: string, b: never) => void
> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^
>a : string
> : ^^^^^^
>b : never
> : ^^^^^

/**
* @satisfies {(a: string, ...args: never) => void}
* @param {string} a
*/
export const fn3 = (a, b) => {};
>fn3 : (a: string, b: never) => void
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^
>(a, b) => {} : (a: string, b: never) => void
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^
>a : string
> : ^^^^^^
>b : never
> : ^^^^^

/**
* @satisfies {(a: string, ...args: never) => void}
* @param {string} a
* @param {number} b
*/
export const fn4 = (a, b) => {};
>fn4 : (a: string, b: number) => void
> : ^ ^^ ^^ ^^ ^^^^^^^^^
>(a, b) => {} : (a: string, b: number) => void
> : ^ ^^ ^^ ^^ ^^^^^^^^^
>a : string
> : ^^^^^^
>b : number
> : ^^^^^^

/**
* @satisfies {(a: string, ...args: number[]) => void}
* @param {string} a
* @param {string} b
*/
export const fn5 = (a, b) => {};
>fn5 : (a: string, b: string) => void
> : ^ ^^ ^^ ^^ ^^^^^^^^^
>(a, b) => {} : (a: string, b: string) => void
> : ^ ^^ ^^ ^^ ^^^^^^^^^
>a : string
> : ^^^^^^
>b : string
> : ^^^^^^

/**
* @satisfies {(a: string, ...args: number[]) => void}
* @param {string} a
* @param {string | number} b
*/
export const fn6 = (a, b) => {};
>fn6 : (a: string, b: string | number) => void
> : ^ ^^ ^^ ^^ ^^^^^^^^^
>(a, b) => {} : (a: string, b: string | number) => void
> : ^ ^^ ^^ ^^ ^^^^^^^^^
>a : string
> : ^^^^^^
>b : string | number
> : ^^^^^^^^^^^^^^^

/** @satisfies {(uuid: string) => void} */
export function fn7(uuid) {}
>fn7 : (uuid: any) => void
> : ^ ^^^^^^^^^^^^^^
>uuid : any
> : ^^^

Loading

0 comments on commit 71b16ea

Please sign in to comment.