Skip to content

Add mechanism for specifying the type of a function declaration #37433

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

Closed
5 tasks done
BPScott opened this issue Mar 17, 2020 · 7 comments
Closed
5 tasks done

Add mechanism for specifying the type of a function declaration #37433

BPScott opened this issue Mar 17, 2020 · 7 comments
Labels
Duplicate An existing issue was already created

Comments

@BPScott
Copy link

BPScott commented Mar 17, 2020

Search terms

function definition type, function expression

Suggestion

I think it would be useful to add a mechanism for specifying the type of a function definition, i.e a type that defines arguments and a return type like type Stringifyer = (arg: number) => string;. This is currently possible by using function expressions but is not possible with function declarations, this feels like a gap that leads to a slightly sub optimal developer experience, as using a function expression results in having to store two types and causes the developer to have to repeat their function names.

Use Cases

Consider a case where I want export a function that should adhere to a predefined interface. In these examples I'll use a trival Stringifyer type as an example but a more concrete use-case would be writing a React component function and wanting to type your function as a React.FunctionComponent.

This is possible using a function expression as follows:

type Stringifyer = (arg: number) => string;

// Define the type of the variable
// Pro: Puts the type close to the function name
// Con: Creates two types (one for the const, one for the anon function)
// Con: repetition of function name
export const stringify1: Stringifyer = function stringify1(arg) {
  return arg.toString();
};

// Type assert the function
// Pro: Creates a single type
// Con: The type is far away from the function name
// Con: repetition of function name
export const stringify2 = function stringify2() {
  return arg.toString();
} as Stringifyer;

Both of these examples have their faults.

  • In both exampels the user is required to repeat the function name as both the variable name and the function name. You could omit the function name but anonymous functions makes debugging harder (and in the case of my React use-case will throw a linting warning as React expects its components to have a name).
  • The first example creates two types - one for the variable and one for the function, when ideally one would do.
  • The second example puts the type far away from the function uuh header(?) - where the function name and arguments are defined.

Examples

A few ideas for what this could look like:

I'm thinking keeping the type close to the name of the function is useful

// Pro: Similar to existing convention of `const x: SomeType = /*...*/;`
// Con: I'd expect a function name to be immediatly before the opening ( of the argument list
export function namedDouble: Stringifyer(arg) {
  return (arg * 2).toString();
}

// Pro: keeps the function name next to the argument list
// Con: I think TS convention tends towards having the type after the name when using colons
export function: Stringifyer namedDouble(arg) {
  return (arg * 2).toString();
}

// Pro: keeps the function name next to the argument list
// Consider: Ambiguity with anonymous function declaration with a generic type argument
// e.g. `const x = function<T>() { /*...*/ }
// Consider: Similarity with angle bracket style type asserts for function expressions
// e.g. `const x = <SomeType> function() { /*...*/ } 
export function<Stringifyer> namedDouble(arg) {
  return (arg * 2).toString();
}

// Pro: uses the same style syntax as existing `as` type asserts
// Con: The type is far away from the function name
export function namedDouble(arg) {
  return (arg * 2).toString();
} as Stringifyer

Out of these three I'm leaning towards option 3 if there are no parser issues. I don't thiiink there will be as the function keyword continues to come first so I guess the parser would know it' is in a function declaration

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.
@ilogico
Copy link

ilogico commented Mar 17, 2020

This reminds me of this suggestion: #34319

@RyanCavanaugh
Copy link
Member

Duplicate #22063

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Mar 17, 2020
@BPScott
Copy link
Author

BPScott commented Mar 17, 2020

Thanks for the links @ilogico and @RyanCavanaugh, it seems my searchbar-fu was not strong enough today.

It looks like they both describe the same root problem, though with slightly different implementation suggestions.
function namedDouble(arg) implements Stringifyer {} is an implementation example mentioned in #34319 that wasn't covered in my statement.

I'd be for rallying around a single issue, and dumping all possible syntaxes into one thread. @RyanCavanaugh Any preference on which of those two issues we should keep open?

@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@JacobWeisenburger
Copy link

Did this functionality ever get added to typescript? I couldn't tell if there was conclusion that was reached on this topic.

I like the following syntax:

interface IMyFuntion {
   (arg: number): string
   prop1: string
}
function myFunction(args) implements IMyFuntion {}

@ilogico
Copy link

ilogico commented Apr 16, 2020

@offg777 It wasn't. I suppose you can vote on the linked issues.

@JacobWeisenburger
Copy link

How do I do that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

5 participants