Description
Search Terms
class method signature
method signature
function overload syntax
function overload
proxy function
proxy function signature
Suggestion
A new syntax for function overloads:
function Func as FunctionSignature
class A {
static Func as FunctionSignature
Func as FunctionSignature
}
This would allow types to be less static, and often more accurate to the purpose of the overloaded function
Right now, we can do something similar using const
-
const: FunctionSignature = function() {}
however, the differences in detailed in #25761 and the lack of any equivalent in classes make this a separate issue.
I'm not dead set on the as
syntax, but I think it fits with what we already have quite well. The checking done on overloads is similar to that of ({ prop: "HI" } as { prop: number })
, and it fits well in and out of classes
It's also worth noting that every use case of this would benefit greatly from #28172
Use Cases
Generic Types
type Pipe<V> = (val: V) => V
function MyFunc as Pipe<string>
// function MyFunc(val: string): string
function MyFunc(...args: any[]): any {
}
Inheritance
function tryInt as typeof parseInt
// function tryInt(s: string, radix?: number): number
function tryInt(...args: [string, number?]) {
const n = parseInt(...args)
if (isNaN(n)) throw "Failed to parse"
return n
}
Combining function implementations
A solution to the problems brought up in #12041 -
function overload as typeof implementation
function overload as typeof otherImplementation
// function overload(num: number): string
// function overload(str: string, num: number): string
function overload(...args: [string, number] | [number]) {
return args.length === 1 ? implementation(...args) : otherImplementation(...args)
}
Which would work particularly well combined with #28172,
function overload as typeof implementation
function overload as typeof otherImplementation
function overload() {
return arguments.length === 1 ? implementation(...arguments) : otherImplementation(...arguments)
}
fully checking the types against the current signature of both implementations, and emitting useful errors
Examples
This came up in the context of an argument parser, where I attempt to parse the values using a direct proxy to another method -
class ArgumentIssue {
confidence: number
}
class Arguments {
async parse(args: string, cb: (val: string) => any = v => v): Promise<{ [key: string]: any }> {
// Follows the return value ^
}
}
class Signature extends Array<Arguments> {
parse as ArgumentBuilder["parse"]
// parse(args: string, cb: (val: string) => any): Promise<{ [key: string]: any }>
parse(a: any, ...args: any[]) {
let Nearest: [Arguments, ArgumentIssue];
for (const overload of this) {
try {
return overload.parse(a, ...args)
} catch (issue) {
if (!(issue instanceof ArgumentIssue)) throw issue;
if (!Nearest || issue.confidence > Nearest[1].confidence)
Nearest = [overload, issue];
}
}
throw Nearest;
}
}
Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.