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

Extend/augment static member of class #39870

Closed
wclr opened this issue Aug 3, 2020 · 7 comments
Closed

Extend/augment static member of class #39870

wclr opened this issue Aug 3, 2020 · 7 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@wclr
Copy link

wclr commented Aug 3, 2020

TypeScript Version: 3.7.x-dev.201xxxxx

Search Terms:

This is probably kind of question, asked it on SO, but din't get the answer.

I have an external module called some-module that defines Some class:

export declare class Some<T> {
   ...
   static create<T>(): Some<T>;
   mapTo<U>(x: U): Some<U>;
}

export default Some

want to redefine the signature of some methods for my project, so I create .d.ts file in my project:

declare module 'some-module' {
  // for prototype methods:
  interface Some<T> {
    // here I can redefine/add signature to method `mapTo`
     mapTo<U extends number>(x: U): Some<U>; 
  }
}

But I need to redefine the signature of static create method, so I tried to do it using namespace:

declare module 'some-module' {
  namespace Some {
     // try to redefine create static method
     create<T extends number>(): Some<T>; 
     // add static method to Some
     added<T extends number>(): Some<T>;
  }
}

Then

const some = Some.create() // <= is NOT redefinded / signature not added
some.mapTo // <= is redefined, new signature added

Some.added // <= static member is added on class

Expected behavior:

The new signature would be added to the existing static method.

Actual behavior:

Signature in namespace for the existing method has no effect.

@wclr wclr changed the title Extend/agument static member of class Extend/augment static member of class Aug 3, 2020
@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Aug 20, 2020
@RyanCavanaugh
Copy link
Member

You can only add signatures via augmentation (this is why we call it augmentation).

@wclr
Copy link
Author

wclr commented Aug 21, 2020

So redefining of signature of a static method is not possible? Is it a current limitation or there is a valid reason for this?

@typescript-bot
Copy link
Collaborator

This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow.

@wclr
Copy link
Author

wclr commented Aug 25, 2020

@RyanCavanaugh?

@RyanCavanaugh
Copy link
Member

@whitecolor Redefinition isn't possible; see e.g. #36146

@InExtremaRes
Copy link

@RyanCavanaugh Sorry to revisit this old thread but I think I have the same issue and it wasn't solved here.

Even if @wclr used the word redefining he has been always thinking about augmentation. Take a new look to the provided example in the OP.

The problem is that if you have a class with an static method, you cannot augment it as you would with instance methods. Look:

class Foo {
    static foo() { }
}
declare namespace Foo {
    export function foo(n: 1): void;
}

This fails with Duplicate identifier 'foo' and does not merge the declarations. An interface Foo won't work here either since then you cannot reach the static part. Most global types has an interface FooConstructor that you can then augment, but I can't change the declaration of the class I wish to augment.

Is there any workaround? Is this behavior expected (and why)? Should I open another issue? Should we take a lot of coffee and try to rewrite TypeScript in Perl?

Thank you. Hope you see this message.

@smac89
Copy link

smac89 commented Feb 1, 2024

@InExtremaRes this is how to do that:

index.d.ts

interface Foo {
}

interface FooConstructor {
   new (): Foo;
   foo(n: number): void
   readonly "prototype": Foo;
}

declare var Foo: FooConstructor;

In JavaScript, you declare your Foo class:

class Foo {
   constructor() {
   }

   static foo(n) {
      console.log(`foo ${n}`);
   }
}

Now let's say you want to add a new static method to Foo, you can add the following to the same index.d.ts file as before, or make a new file:

interface FooConstructor {
   bar(s: string): void
}

In a regular .ts or .js file, add the implementation of Foo.bar (I chose ts in this case):

if (!Foo.bar) {
   Foo.bar = function(s: string): void {
      console.log(`bar: ${s}`);
   }
}

Note that if you had just written Foo in typescript, you won't need to do anything more than what we did in the last step above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

5 participants