mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 18:04:18 -05:00
Check overload tag against implementation (#52474)
This commit is contained in:
committed by
GitHub
parent
2976b6b703
commit
4b534dc859
@@ -748,6 +748,7 @@ import {
|
||||
JSDocMemberName,
|
||||
JSDocNullableType,
|
||||
JSDocOptionalType,
|
||||
JSDocOverloadTag,
|
||||
JSDocParameterTag,
|
||||
JSDocPrivateTag,
|
||||
JSDocPropertyLikeTag,
|
||||
@@ -38692,6 +38693,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
lastSeenNonAmbientDeclaration = node as FunctionLikeDeclaration;
|
||||
}
|
||||
}
|
||||
if (isInJSFile(current) && isFunctionLike(current) && current.jsDoc) {
|
||||
for (const node of current.jsDoc) {
|
||||
if (node.tags) {
|
||||
for (const tag of node.tags) {
|
||||
if (isJSDocOverloadTag(tag)) {
|
||||
hasOverloads = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38743,8 +38755,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const bodySignature = getSignatureFromDeclaration(bodyDeclaration);
|
||||
for (const signature of signatures) {
|
||||
if (!isImplementationCompatibleWithOverload(bodySignature, signature)) {
|
||||
const errorNode = signature.declaration && isJSDocSignature(signature.declaration)
|
||||
? (signature.declaration.parent as JSDocOverloadTag | JSDocCallbackTag).tagName
|
||||
: signature.declaration;
|
||||
addRelatedInfo(
|
||||
error(signature.declaration, Diagnostics.This_overload_signature_is_not_compatible_with_its_implementation_signature),
|
||||
error(errorNode, Diagnostics.This_overload_signature_is_not_compatible_with_its_implementation_signature),
|
||||
createDiagnosticForNode(bodyDeclaration, Diagnostics.The_implementation_signature_is_declared_here)
|
||||
);
|
||||
break;
|
||||
|
||||
73
tests/baselines/reference/overloadTag1.errors.txt
Normal file
73
tests/baselines/reference/overloadTag1.errors.txt
Normal file
@@ -0,0 +1,73 @@
|
||||
tests/cases/conformance/jsdoc/overloadTag1.js(7,5): error TS2394: This overload signature is not compatible with its implementation signature.
|
||||
tests/cases/conformance/jsdoc/overloadTag1.js(25,10): error TS2769: No overload matches this call.
|
||||
Overload 1 of 2, '(a: number, b: number): number', gave the following error.
|
||||
Argument of type 'string' is not assignable to parameter of type 'number'.
|
||||
Overload 2 of 2, '(a: string, b: boolean): string', gave the following error.
|
||||
Argument of type 'string' is not assignable to parameter of type 'boolean'.
|
||||
tests/cases/conformance/jsdoc/overloadTag1.js(43,1): error TS2769: No overload matches this call.
|
||||
Overload 1 of 2, '(a: number, b: number): number', gave the following error.
|
||||
Argument of type 'string' is not assignable to parameter of type 'number'.
|
||||
Overload 2 of 2, '(a: string, b: boolean): string', gave the following error.
|
||||
Argument of type 'string' is not assignable to parameter of type 'boolean'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/overloadTag1.js (3 errors) ====
|
||||
/**
|
||||
* @overload
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*
|
||||
* @overload
|
||||
~~~~~~~~
|
||||
!!! error TS2394: This overload signature is not compatible with its implementation signature.
|
||||
!!! related TS2750 tests/cases/conformance/jsdoc/overloadTag1.js:16:17: The implementation signature is declared here.
|
||||
* @param {string} a
|
||||
* @param {boolean} b
|
||||
* @returns {string}
|
||||
*
|
||||
* @param {string | number} a
|
||||
* @param {string | number} b
|
||||
* @returns {string | number}
|
||||
*/
|
||||
export function overloaded(a,b) {
|
||||
if (typeof a === "string" && typeof b === "string") {
|
||||
return a + b;
|
||||
} else if (typeof a === "number" && typeof b === "number") {
|
||||
return a + b;
|
||||
}
|
||||
throw new Error("Invalid arguments");
|
||||
}
|
||||
var o1 = overloaded(1,2)
|
||||
var o2 = overloaded("zero", "one")
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2769: No overload matches this call.
|
||||
!!! error TS2769: Overload 1 of 2, '(a: number, b: number): number', gave the following error.
|
||||
!!! error TS2769: Argument of type 'string' is not assignable to parameter of type 'number'.
|
||||
!!! error TS2769: Overload 2 of 2, '(a: string, b: boolean): string', gave the following error.
|
||||
!!! error TS2769: Argument of type 'string' is not assignable to parameter of type 'boolean'.
|
||||
var o3 = overloaded("a",false)
|
||||
|
||||
/**
|
||||
* @overload
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*
|
||||
* @overload
|
||||
* @param {string} a
|
||||
* @param {boolean} b
|
||||
* @returns {string}
|
||||
*/
|
||||
export function uncheckedInternally(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
uncheckedInternally(1,2)
|
||||
uncheckedInternally("zero", "one")
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2769: No overload matches this call.
|
||||
!!! error TS2769: Overload 1 of 2, '(a: number, b: number): number', gave the following error.
|
||||
!!! error TS2769: Argument of type 'string' is not assignable to parameter of type 'number'.
|
||||
!!! error TS2769: Overload 2 of 2, '(a: string, b: boolean): string', gave the following error.
|
||||
!!! error TS2769: Argument of type 'string' is not assignable to parameter of type 'boolean'.
|
||||
|
||||
102
tests/baselines/reference/overloadTag1.js
Normal file
102
tests/baselines/reference/overloadTag1.js
Normal file
@@ -0,0 +1,102 @@
|
||||
//// [overloadTag1.js]
|
||||
/**
|
||||
* @overload
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*
|
||||
* @overload
|
||||
* @param {string} a
|
||||
* @param {boolean} b
|
||||
* @returns {string}
|
||||
*
|
||||
* @param {string | number} a
|
||||
* @param {string | number} b
|
||||
* @returns {string | number}
|
||||
*/
|
||||
export function overloaded(a,b) {
|
||||
if (typeof a === "string" && typeof b === "string") {
|
||||
return a + b;
|
||||
} else if (typeof a === "number" && typeof b === "number") {
|
||||
return a + b;
|
||||
}
|
||||
throw new Error("Invalid arguments");
|
||||
}
|
||||
var o1 = overloaded(1,2)
|
||||
var o2 = overloaded("zero", "one")
|
||||
var o3 = overloaded("a",false)
|
||||
|
||||
/**
|
||||
* @overload
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*
|
||||
* @overload
|
||||
* @param {string} a
|
||||
* @param {boolean} b
|
||||
* @returns {string}
|
||||
*/
|
||||
export function uncheckedInternally(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
uncheckedInternally(1,2)
|
||||
uncheckedInternally("zero", "one")
|
||||
|
||||
|
||||
//// [overloadTag1.js]
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.uncheckedInternally = exports.overloaded = void 0;
|
||||
/**
|
||||
* @overload
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*
|
||||
* @overload
|
||||
* @param {string} a
|
||||
* @param {boolean} b
|
||||
* @returns {string}
|
||||
*
|
||||
* @param {string | number} a
|
||||
* @param {string | number} b
|
||||
* @returns {string | number}
|
||||
*/
|
||||
function overloaded(a, b) {
|
||||
if (typeof a === "string" && typeof b === "string") {
|
||||
return a + b;
|
||||
}
|
||||
else if (typeof a === "number" && typeof b === "number") {
|
||||
return a + b;
|
||||
}
|
||||
throw new Error("Invalid arguments");
|
||||
}
|
||||
exports.overloaded = overloaded;
|
||||
var o1 = overloaded(1, 2);
|
||||
var o2 = overloaded("zero", "one");
|
||||
var o3 = overloaded("a", false);
|
||||
/**
|
||||
* @overload
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*
|
||||
* @overload
|
||||
* @param {string} a
|
||||
* @param {boolean} b
|
||||
* @returns {string}
|
||||
*/
|
||||
function uncheckedInternally(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
exports.uncheckedInternally = uncheckedInternally;
|
||||
uncheckedInternally(1, 2);
|
||||
uncheckedInternally("zero", "one");
|
||||
|
||||
|
||||
//// [overloadTag1.d.ts]
|
||||
export function overloaded(a: number, b: number): number;
|
||||
export function overloaded(a: string, b: boolean): string;
|
||||
export function uncheckedInternally(a: number, b: number): number;
|
||||
export function uncheckedInternally(a: string, b: boolean): string;
|
||||
78
tests/baselines/reference/overloadTag1.symbols
Normal file
78
tests/baselines/reference/overloadTag1.symbols
Normal file
@@ -0,0 +1,78 @@
|
||||
=== tests/cases/conformance/jsdoc/overloadTag1.js ===
|
||||
/**
|
||||
* @overload
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*
|
||||
* @overload
|
||||
* @param {string} a
|
||||
* @param {boolean} b
|
||||
* @returns {string}
|
||||
*
|
||||
* @param {string | number} a
|
||||
* @param {string | number} b
|
||||
* @returns {string | number}
|
||||
*/
|
||||
export function overloaded(a,b) {
|
||||
>overloaded : Symbol(overloaded, Decl(overloadTag1.js, 0, 0))
|
||||
>a : Symbol(a, Decl(overloadTag1.js, 15, 27))
|
||||
>b : Symbol(b, Decl(overloadTag1.js, 15, 29))
|
||||
|
||||
if (typeof a === "string" && typeof b === "string") {
|
||||
>a : Symbol(a, Decl(overloadTag1.js, 15, 27))
|
||||
>b : Symbol(b, Decl(overloadTag1.js, 15, 29))
|
||||
|
||||
return a + b;
|
||||
>a : Symbol(a, Decl(overloadTag1.js, 15, 27))
|
||||
>b : Symbol(b, Decl(overloadTag1.js, 15, 29))
|
||||
|
||||
} else if (typeof a === "number" && typeof b === "number") {
|
||||
>a : Symbol(a, Decl(overloadTag1.js, 15, 27))
|
||||
>b : Symbol(b, Decl(overloadTag1.js, 15, 29))
|
||||
|
||||
return a + b;
|
||||
>a : Symbol(a, Decl(overloadTag1.js, 15, 27))
|
||||
>b : Symbol(b, Decl(overloadTag1.js, 15, 29))
|
||||
}
|
||||
throw new Error("Invalid arguments");
|
||||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
}
|
||||
var o1 = overloaded(1,2)
|
||||
>o1 : Symbol(o1, Decl(overloadTag1.js, 23, 3))
|
||||
>overloaded : Symbol(overloaded, Decl(overloadTag1.js, 0, 0))
|
||||
|
||||
var o2 = overloaded("zero", "one")
|
||||
>o2 : Symbol(o2, Decl(overloadTag1.js, 24, 3))
|
||||
>overloaded : Symbol(overloaded, Decl(overloadTag1.js, 0, 0))
|
||||
|
||||
var o3 = overloaded("a",false)
|
||||
>o3 : Symbol(o3, Decl(overloadTag1.js, 25, 3))
|
||||
>overloaded : Symbol(overloaded, Decl(overloadTag1.js, 0, 0))
|
||||
|
||||
/**
|
||||
* @overload
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*
|
||||
* @overload
|
||||
* @param {string} a
|
||||
* @param {boolean} b
|
||||
* @returns {string}
|
||||
*/
|
||||
export function uncheckedInternally(a, b) {
|
||||
>uncheckedInternally : Symbol(uncheckedInternally, Decl(overloadTag1.js, 25, 30))
|
||||
>a : Symbol(a, Decl(overloadTag1.js, 38, 36))
|
||||
>b : Symbol(b, Decl(overloadTag1.js, 38, 38))
|
||||
|
||||
return a + b;
|
||||
>a : Symbol(a, Decl(overloadTag1.js, 38, 36))
|
||||
>b : Symbol(b, Decl(overloadTag1.js, 38, 38))
|
||||
}
|
||||
uncheckedInternally(1,2)
|
||||
>uncheckedInternally : Symbol(uncheckedInternally, Decl(overloadTag1.js, 25, 30))
|
||||
|
||||
uncheckedInternally("zero", "one")
|
||||
>uncheckedInternally : Symbol(uncheckedInternally, Decl(overloadTag1.js, 25, 30))
|
||||
|
||||
112
tests/baselines/reference/overloadTag1.types
Normal file
112
tests/baselines/reference/overloadTag1.types
Normal file
@@ -0,0 +1,112 @@
|
||||
=== tests/cases/conformance/jsdoc/overloadTag1.js ===
|
||||
/**
|
||||
* @overload
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*
|
||||
* @overload
|
||||
* @param {string} a
|
||||
* @param {boolean} b
|
||||
* @returns {string}
|
||||
*
|
||||
* @param {string | number} a
|
||||
* @param {string | number} b
|
||||
* @returns {string | number}
|
||||
*/
|
||||
export function overloaded(a,b) {
|
||||
>overloaded : { (a: number, b: number): number; (a: string, b: boolean): string; }
|
||||
>a : string | number
|
||||
>b : string | number
|
||||
|
||||
if (typeof a === "string" && typeof b === "string") {
|
||||
>typeof a === "string" && typeof b === "string" : boolean
|
||||
>typeof a === "string" : boolean
|
||||
>typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>a : string | number
|
||||
>"string" : "string"
|
||||
>typeof b === "string" : boolean
|
||||
>typeof b : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>b : string | number
|
||||
>"string" : "string"
|
||||
|
||||
return a + b;
|
||||
>a + b : string
|
||||
>a : string
|
||||
>b : string
|
||||
|
||||
} else if (typeof a === "number" && typeof b === "number") {
|
||||
>typeof a === "number" && typeof b === "number" : boolean
|
||||
>typeof a === "number" : boolean
|
||||
>typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>a : string | number
|
||||
>"number" : "number"
|
||||
>typeof b === "number" : boolean
|
||||
>typeof b : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>b : string | number
|
||||
>"number" : "number"
|
||||
|
||||
return a + b;
|
||||
>a + b : number
|
||||
>a : number
|
||||
>b : number
|
||||
}
|
||||
throw new Error("Invalid arguments");
|
||||
>new Error("Invalid arguments") : Error
|
||||
>Error : ErrorConstructor
|
||||
>"Invalid arguments" : "Invalid arguments"
|
||||
}
|
||||
var o1 = overloaded(1,2)
|
||||
>o1 : number
|
||||
>overloaded(1,2) : number
|
||||
>overloaded : { (a: number, b: number): number; (a: string, b: boolean): string; }
|
||||
>1 : 1
|
||||
>2 : 2
|
||||
|
||||
var o2 = overloaded("zero", "one")
|
||||
>o2 : never
|
||||
>overloaded("zero", "one") : never
|
||||
>overloaded : { (a: number, b: number): number; (a: string, b: boolean): string; }
|
||||
>"zero" : "zero"
|
||||
>"one" : "one"
|
||||
|
||||
var o3 = overloaded("a",false)
|
||||
>o3 : string
|
||||
>overloaded("a",false) : string
|
||||
>overloaded : { (a: number, b: number): number; (a: string, b: boolean): string; }
|
||||
>"a" : "a"
|
||||
>false : false
|
||||
|
||||
/**
|
||||
* @overload
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*
|
||||
* @overload
|
||||
* @param {string} a
|
||||
* @param {boolean} b
|
||||
* @returns {string}
|
||||
*/
|
||||
export function uncheckedInternally(a, b) {
|
||||
>uncheckedInternally : { (a: number, b: number): number; (a: string, b: boolean): string; }
|
||||
>a : any
|
||||
>b : any
|
||||
|
||||
return a + b;
|
||||
>a + b : any
|
||||
>a : any
|
||||
>b : any
|
||||
}
|
||||
uncheckedInternally(1,2)
|
||||
>uncheckedInternally(1,2) : number
|
||||
>uncheckedInternally : { (a: number, b: number): number; (a: string, b: boolean): string; }
|
||||
>1 : 1
|
||||
>2 : 2
|
||||
|
||||
uncheckedInternally("zero", "one")
|
||||
>uncheckedInternally("zero", "one") : never
|
||||
>uncheckedInternally : { (a: number, b: number): number; (a: string, b: boolean): string; }
|
||||
>"zero" : "zero"
|
||||
>"one" : "one"
|
||||
|
||||
48
tests/cases/conformance/jsdoc/overloadTag1.ts
Normal file
48
tests/cases/conformance/jsdoc/overloadTag1.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
// @checkJs: true
|
||||
// @allowJs: true
|
||||
// @outdir: foo
|
||||
// @declaration: true
|
||||
// @filename: overloadTag1.js
|
||||
/**
|
||||
* @overload
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*
|
||||
* @overload
|
||||
* @param {string} a
|
||||
* @param {boolean} b
|
||||
* @returns {string}
|
||||
*
|
||||
* @param {string | number} a
|
||||
* @param {string | number} b
|
||||
* @returns {string | number}
|
||||
*/
|
||||
export function overloaded(a,b) {
|
||||
if (typeof a === "string" && typeof b === "string") {
|
||||
return a + b;
|
||||
} else if (typeof a === "number" && typeof b === "number") {
|
||||
return a + b;
|
||||
}
|
||||
throw new Error("Invalid arguments");
|
||||
}
|
||||
var o1 = overloaded(1,2)
|
||||
var o2 = overloaded("zero", "one")
|
||||
var o3 = overloaded("a",false)
|
||||
|
||||
/**
|
||||
* @overload
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*
|
||||
* @overload
|
||||
* @param {string} a
|
||||
* @param {boolean} b
|
||||
* @returns {string}
|
||||
*/
|
||||
export function uncheckedInternally(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
uncheckedInternally(1,2)
|
||||
uncheckedInternally("zero", "one")
|
||||
Reference in New Issue
Block a user