Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript bindings for class not working?

I have a definition file, let's call it someclass.d.ts that looks more or less like this:

declare class SomeClass {
    static write : {
        doThing(name: string) : string
    }

    static get : {
        doThing2(count: number): string
    }
}

This matches the actual class in someclass.ts

export default class SomeClass {
    static write = {
        doThing(name) {
            return "foo1";
        }
    }

    static get = {
        doThing2(count) {
            return "foo2";
        }
    }
}

And then in my mainThing.ts, which actually uses the SomeClass:

/// <reference types="./someclass" />
import SomeClass from './someclass.ts';
SomeClass.write.doThing("dummyexample");

If I mouseover doThing in mainThing.ts/someclass.ts in VSCode, it acts like everything is implicit any typed, which tells me I'm doing something wrong. I just don't know what.

I'm guessing that I'm doing the declaration wrong for those class member blocks, but I'm not sure what the correct way to do it is; trying to do static write = { seems to make it look for function bodies...

What am I doing wrong? Thank you!

Edit: I am aware I am not required to have a separate definition file, but I want to do so in the name of readable code. The real signature for doThing looks more like

doThing({ name, email, password, p4, p5, p6 }
    : { name: string, email: string, password: string, p4: string, p5: number, p6: string }) 
    : Type1<Type2<Type3>>

Edit 2: Additionally, SomeClass doesn't actually need to be a class... maybe TypeScript namespaces (or something else) would be more appropriate? I'm mostly just trying to organize a large number of utility methods in a way that isn't overwhelming. Everything is deliberately static for this reason; there's no point instantiating SomeClass when it doesn't have any state.

like image 238
user3534080 Avatar asked May 25 '26 15:05

user3534080


1 Answers

.d.ts declaration file is meant to type-annotate .js file, not .ts file.

I can see that you're trying to use the Java convention here. Thing is JS class is quite different to Java class. TS is designed for JS so it won't serve you the way you expect it to. Although you can use .d.ts with .ts file, the usage that involves class is very tedious, that it beats the purpose of readable code.

My suggestion to your problem is to use plain object instead of class-static couple, since JS class is really syntax sugar to object.

someclass.d.ts

declare interface SomeClass {
  write: {
    doThing(name: string): string;
  };

  get: {
    doThing2(count: number): string;
  };
}

someclass.ts

const SomeClass: SomeClass = {
  write: {
    doThing(name) {
      return "foo1";
    }
  },

  get: {
    doThing2(count) {
      return "foo2";
    }
  }
};

export default SomeClass;

mainThing.ts

import SomeClass from './someclass.ts';
SomeClass.write.doThing(1);
// [TS ERROR] Argument of type '1' is not assignable to parameter of type 'string'.

Side Note:

I said earlier that usage involving class is tedious. Here's how to do it if you really want to use class-static:

someclass.d.ts

declare abstract class SomeAbstractClass {
  static write: {
    doThing(name: string): string;
  }
}

someclass.ts

export default class SomeClass extends SomeAbstractClass {
  static write = {
    // you still need to re-write the function signature in class impl
    doThing(name: string) {
      return "foo1";
    }

    // all it does is just to warn you when you accidentally write:
    doThing(name: number) { // ERROR: should be string not number
      return "foo1";
    }
  }
}

You cannot use class SomeClass implements SomeClassInterface, cus implements keyword only governs the instance side of class, not static side.

like image 97
hackape Avatar answered May 28 '26 07:05

hackape