Skip to content
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

[Proposal] Initializer syntax for function types #21572

Closed
AlCalzone opened this issue Feb 2, 2018 · 3 comments
Closed

[Proposal] Initializer syntax for function types #21572

AlCalzone opened this issue Feb 2, 2018 · 3 comments
Labels
Duplicate An existing issue was already created

Comments

@AlCalzone
Copy link
Contributor

AlCalzone commented Feb 2, 2018

Using function types, it's possible to define types for functions with additional properties tacked on, e.g.

interface fnWithProp {
    (abc: string): string;
    foo: number;
}

In order to initialize variables of those types, one currently has to jump through hoops because the naive attempt does not work:

// Error: 
// Type '(str: any) => any' is not assignable to type 'fnWithProp'.
// Property 'foo' is missing in type '(str: any) => any'.
var abc: fnWithProp = (str) => str;
abc.foo = 7;

By explicitly casting the function to the correct type, one can avoid the error, but now TypeScript never checks if foo is assigned (even with strictPropertyInitialization = true):

var abc = ((str) => str) as fnWithProp;
console.log(abc.foo); // undefined

A working version looks like this

var abc = Object.assign(((str) => str), {
    foo: 7,
});

but abc is now being inferred as the rather cryptic type ((str: any) => any) & { foo: number }.

As an attempt to solve this problem, I propose an initializer syntax for these kinds of function types, which is similar to the object literal syntax:

var abc: fnWithProp = {
    (str) => {
        /* do something */
        return str;
    },
    foo: 7,
    /* optional: more properties */
};

or an alternative using the this keyword for the function body:

var abc: fnWithProp = {
    this: (str) => {
        /* do something */
        return str;
    },
    foo: 7,
    /* optional: more properties */
};

A usage example:

interface fnWithProp {
    (abc: number): number;
    foo: number;
}

function doSomething(transform: fnWithProp) { 
    return transform(transform.foo + 1);
}

doSomething({ this: (abc) => abc, foo: 7 });
@ghost
Copy link

ghost commented Feb 2, 2018

This would fall out of scope of the design goals since it would add new expression-level syntax. Besides, const obj = { this: str => str }; is already valid syntax.

Anyway, you can combine the interface declaration with Object.assign with no problem:

interface fnWithProp {
    (abc: string): string;
    foo: number;
}
const o: fnWithProp = Object.assign((abc: string) => abc.toUpperCase(), { foo: 1 });

EDIT: You will need to explicitly type abc: string since we don't get a contextual type there.

@ghost ghost added the Out of Scope This idea sits outside of the TypeScript language design constraints label Feb 2, 2018
@mhegazy
Copy link
Contributor

mhegazy commented Feb 2, 2018

The underlying issue is tracked by #15868. there is not an easy/ergonomic way in the language to create one of these functions that have properties. the best we have today is a function and namespace combo:

interface fnWithProp {
    (abc: string): string;
    foo: number;
}

function f(a: string) { return a; }
namespace f {
    export var foo: number;
}

var abc: fnWithProp = f;

@mhegazy mhegazy added Duplicate An existing issue was already created and removed Out of Scope This idea sits outside of the TypeScript language design constraints labels Feb 2, 2018
@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

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

No branches or pull requests

3 participants