104

I have several utility functions. What is the best way to package these up, and then import them?

This is what I am trying to do:

import * as util from './util'

export class myClass{
     constructor()
     {
           util.doSomething("test");
     }
}

Then in the class:

export class Util{
    doSomething(val: string){ return val;}

    doSomethingElse(val: string){ return val;}
}

The error message I get from VS is:

Property doSomething does not exist on type util.

Trinimon
  • 13,839
  • 9
  • 44
  • 60
Greg Gum
  • 33,478
  • 39
  • 162
  • 233

6 Answers6

168

If you create a file utils.ts which contains

export default class Utils {
    static doSomething(val: string) { return val; }
    static doSomethingElse(val: string) { return val; }
}

then you can simplify your client code like this:

import Utils from './utils'

export class MyClass {
     constructor()
     {
         Utils.doSomething("test");
     }
}
k7sleeper
  • 2,689
  • 1
  • 17
  • 11
  • Do the methods have to be static? Can't an instance of Utils class be created an used? – user728630 Sep 20 '16 at 02:40
  • 7
    @GregGum Wrapping your stateless functions in a class just for the heck of it is a bad idea, because it breaks module optimization techniques like tree-shaking. You should export everything as close to the top level of the module as possible. – Asad Saeeduddin Sep 20 '16 at 02:57
  • 25
    Based on comments on my answer it seems I didn't sufficiently clarify this in my previous comment: wrapping entirely stateless functions as static members of a `class Utils`, as shown in this answer, is a **bad idea**. It will break module optimization for no benefit whatsoever to you. If your members, like `doSomething` and `doSomethingElse`, are entirely stateless, and do not reference private members of a class, they should not be in a class at all. You should directly export them using `export function doSomething ...`. – Asad Saeeduddin Jan 27 '18 at 19:53
  • @asad-saeeduddin - Any reason not use a `namespace` to wrap the functions? – Jack Mar 05 '18 at 18:56
  • @Jack Yes, it breaks tree shaking. – Asad Saeeduddin Mar 05 '18 at 19:19
  • @k7sleeper how does this work with a shared module? Just creating the file and importing it into a component wouldn't pack and reuse the method would it? – Ben Racicot Feb 28 '19 at 14:29
  • What's a "shared module"? Shared between client code and server code? For packing browser code I use webpack. – k7sleeper Mar 15 '19 at 11:45
  • Is it really better to have an module, that used in all components (so each of them as a reference to the instance or creating instances for themself) as clean static util? I guess not. – akop Apr 09 '19 at 13:45
  • 1
    Agreed with @GregGum same has been conveyed in type script docs. Have a look: https://medium.com/@OlegVaraksin/what-is-the-best-way-to-write-utilities-in-typescript-e3cae916fe30 – Vaibhav Jun 21 '19 at 19:20
  • @k7sleeper if utils.ts is imported at multiple classes/files, all class members/functions will be imported multiple times event if its not needed. Tree shaking does not work with this approach. – Nikhil Nov 08 '21 at 06:30
  • The docs (article) above about not using static util class also adds `Unless it increases expressivity or intent in a clearly useful way` – Drenai Feb 19 '23 at 23:38
51

There's a couple problems here:

  1. You're not instantiating anything, and doSomething is an instance method
  2. When you do import * as util, util represents the module, not an object in it.

If you want Util, you should just import that:

import { Util } from './util'

Next, you should instantiate Util, before finally calling the method on it:

var u = new Util();
u.doSomething("test");

Here's your code patched up:

import { Util } from './util'

export class MyClass{
     constructor()
     {
         var u = new Util();
         u.doSomething("test");
     }
}

All that said, there seems to be something odd about the way you're using your utils. This is totally personal opinion, but I wouldn't invoke methods that "do something", i.e. cause side effects, in a constructor.

Also, the methods in Util don't really look like they need to be in that class, since the class holds no state that they depend on. You can always export regular functions from a module. If you wrote your utils module like this:

export function doSomething(val: string) { return val; }

export function doSomethingElse(val: string) { return val; }

you'd be exporting your functions directly and would sidestep the instantiation hassle, and in fact your original code would work correctly as is.

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
  • 3
    Util modules should'nt be instantiated as an instance with the `new` keyword. If you want to follow standard conventions, and reduce execution context creation, the Util class methods should be static methods, accessed via `Util.doSomething()` – Drenai Jan 27 '18 at 13:23
  • 4
    @Ryan You are wrong. If the functionality you are exporting is dependent on some state, you should export it as an instantiable class. If it is stateless, as in this case, *you should export it as top level independent exports*. If you just cram them into a static class for no reason you break tree shaking for no benefit to yourself. – Asad Saeeduddin Jan 27 '18 at 19:47
  • The original question describes a Util that does not depend on any state. They are straight static functions. Are you saying that tree shaking will break unless you instantiatle the Util? – Drenai Jan 27 '18 at 19:51
  • 3
    No, I am saying tree shaking will break if you do `class Util` at all. Since the members are stateless (which I mentioned in my answer, and at this point in two different comments), you *should not have a class at all*. You should export the members directly, in order to exploit tree shaking. – Asad Saeeduddin Jan 27 '18 at 19:52
  • How can i wrap your methods doSomething, doSomethingElse in a namespace called MyUtilsNS to avoid conflicting with another library that also has doSomething, doSomethingElse ? – joedotnot Jul 20 '18 at 14:41
  • @joedotnot You can't, but when importing them you can alias them however you want. For example you can import them as `import { doSomething as fooDoSomething } from "myfoomodule"`. – Asad Saeeduddin Jul 20 '18 at 18:23
  • Similarly you can also just alias the whole import `import * as MyFooModule from "myfoomodule"` and use `MyFooModules.doSomething`, but be aware that this sort of thing is liable to cause issues with tree shaking. – Asad Saeeduddin Jul 20 '18 at 18:24
  • @AsadSaeeduddin I guess your comment regarding tree shacking worth to be added to the answer. – Alexander Ivanchenko Mar 16 '23 at 21:37
16

Alternative way:

  1. Export constants in your utils.ts file:

    export const doSomething = (val: string): any => {
      return val;
    };
    
    export const doSomethingElse = (val: string): any => {
      return val;
    };
    
  2. Import and use this methods in main *.ts file:

    import { doSomething, doSomethingElse } from './util';
    ...
    let value1 = doSomething('abc');
    let value2 = doSomethingElse ('efg');
    
BuZZ-dEE
  • 6,075
  • 12
  • 66
  • 96
Renat Gatin
  • 6,053
  • 5
  • 37
  • 58
  • 1
    This worked best for my situation. I was able to `import * as Util from './util';` and use functions as `Util.doSomething('abc');`. – Kentaro Sep 21 '20 at 09:04
4

Or you could export is as an object literal:

export const Util = {
    doSomething(val: string){ return val;},
    doSomethingElse(val: string{ return val;}
}
Max Rahder
  • 41
  • 3
  • This is probably the best way of doing it. I would usually create the functions as `const` at the top of the file, and then use `export const Util { doSomething, doSomethingElse }` – Drenai Nov 06 '19 at 20:14
1

You can also create a util.ts class which has a function to export

export const formatDateOfBirth = 
(dob: string) : string => `${dob.substring(0, 4)}-${dob.substring(4, 6)}-${dob.substring(6, 8)}`;

Now you can import the method as below, shared folder structure is src > app > shared, I am calling this import inside src > app > shelf > shelf.component.ts file

import { formatDateOfBirth } from '../shared/utils/util';
public getFormattedDate(dob: string):string{
  return formatDateOfBirth(dob);
}
BuZZ-dEE
  • 6,075
  • 12
  • 66
  • 96
vijay
  • 609
  • 5
  • 9
0

I think I figured out the best way to do it, that is flexible and suits all cases.

First of all, utility functions should be exported independently, no need to wrap them in a class. This allows tree-shaking to work with the file's exports.

utils.ts

export function helper() { 
  console.log('help is provided') 
}

Than you can import and use the functions directly, if you want tree-shakability and don't care about mocking utils functions (which you don't in most cases, if they are written correctly).

But, if for some components you want to mock them, you can still do it. For Angular, you should do the following:

tokens.ts

import * as utils from 'utils.ts';
export const utilsToken = new InjectionToken<typeof utils>('UtilsToken')

app.module.ts

import * as utils from 'utils.ts';
import { utilsToken } from 'tokens.ts';
@NgModule({
    providers: [{ provide: utilsToken, useValue: utils }]
})  

Having this set up, you can inject your utils in any component instead of using them directly:

component.ts

import * as utils from 'utils.ts';
import { utilsToken } from 'tokens.ts';

@Component({
})
export class Component {
constructor(@Inject(utilsToken) private _utils: typeof utils) {
  this._utils.helper();
}

component.spec.ts

import * as utils from 'utils.ts';
import { utilsToken } from 'tokens.ts';

...
await TestBed.configureTestingModule({
     providers: [{ provide: utilsToken, useValue: mockUtils }],
}).compileComponents(),

Then you can use your utils directly in some components and inject them in others (that require mocked utils version for testing)

Yaroslav Larin
  • 209
  • 2
  • 6