Как структурировать служебный класс

У меня есть несколько полезных функций. Каков наилучший способ упаковать их, а затем импортировать?

Вот что я пытаюсь сделать:

import * as util from './util'

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

Затем в классе:

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

    doSomethingElse(val: string{ return val;}
}

Сообщение об ошибке, которое я получаю от VS:

Property doSomething does not exist on type util.


person Greg Gum    schedule 25.09.2015    source источник


Ответы (5)


Если вы создаете файл utils.ts, который содержит

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

то вы можете упростить свой клиентский код следующим образом:

import Utils from './utils'

export class MyClass {
     constructor()
     {
         Utils.doSomething("test");
     }
}
person k7sleeper    schedule 06.06.2016
comment
Должны ли методы быть статическими? Нельзя ли создать экземпляр класса Utils? - person user728630; 20.09.2016
comment
@GregGum Оборачивать ваши функции без состояния в класс просто так, черт возьми, это плохая идея, потому что это нарушает методы оптимизации модулей, такие как встряхивание дерева. Вы должны экспортировать все как можно ближе к верхнему уровню модуля. - person Asad Saeeduddin; 20.09.2016
comment
Судя по комментариям к моему ответу, кажется, я недостаточно разъяснил это в своем предыдущем комментарии: обертывание полностью функций без состояния как статических членов class Utils, как показано в этом ответе, является плохой идеей. Это нарушит оптимизацию модуля без какой-либо пользы для вас. Если ваши члены, такие как doSomething и doSomethingElse, полностью не имеют состояния и не ссылаются на частные члены класса, они вообще не должны быть в классе. Вы должны напрямую экспортировать их, используя export function doSomething .... - person Asad Saeeduddin; 27.01.2018
comment
@ asad-saeeduddin - Есть ли причина не использовать namespace для переноса функций? - person Jack; 05.03.2018
comment
@ Джек Да, это предотвращает тряску дерева. - person Asad Saeeduddin; 05.03.2018
comment
@ k7sleeper, как это работает с общим модулем? Простое создание файла и его импорт в компонент не приведет к упаковке и повторному использованию метода, не так ли? - person Ben Racicot; 28.02.2019
comment
Что такое общий модуль? Разделяется между клиентским кодом и серверным кодом? Для упаковки кода браузера я использую webpack. - person k7sleeper; 15.03.2019
comment
Действительно ли лучше иметь модуль, который используется во всех компонентах (то есть каждый из них как ссылка на экземпляр или создание экземпляров для себя) как чистая статическая утилита? Думаю, нет. - person akop; 09.04.2019
comment
Согласовано с @GregGum, то же самое было передано в документах типового сценария. Посмотрите: medium .com/@ОлегВараксин/ - person Vaibhav; 21.06.2019

Здесь есть пара проблем:

  1. Вы ничего не создаете, а doSomething является методом экземпляра
  2. Когда вы делаете import * as util, util представляет модуль, а не объект в нем.

Если вы хотите Util, вы должны просто импортировать это:

import { Util } from './util'

Затем вы должны создать экземпляр Util, прежде чем, наконец, вызвать для него метод:

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

Вот ваш код исправлен:

import { Util } from './util'

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

Все это говорит о том, что в том, как вы используете свои утилиты, есть что-то странное. Это сугубо личное мнение, но я бы не стал вызывать в конструкторе методы, которые "что-то делают", то есть вызывают побочные эффекты.

Кроме того, методы в Util на самом деле не выглядят так, как будто они должны быть в этом классе, поскольку класс не содержит состояния, от которого они зависят. Вы всегда можете экспортировать обычные функции из модуля. Если вы написали свой модуль utils следующим образом:

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

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

вы бы экспортировали свои функции напрямую и обошли бы проблемы с созданием экземпляров, и на самом деле ваш исходный код будет работать правильно как есть.

person Asad Saeeduddin    schedule 25.09.2015
comment
Модули Util не должны создаваться как экземпляры с ключевым словом new. Если вы хотите следовать стандартным соглашениям и уменьшить создание контекста выполнения, методы класса Util должны быть статическими методами, доступ к которым осуществляется через Util.doSomething(). - person Drenai; 27.01.2018
comment
@ Райан Ты ошибаешься. Если экспортируемая вами функциональность зависит от некоторого состояния, вы должны экспортировать ее как инстанцируемый класс. Если он не имеет состояния, как в этом случае, вы должны экспортировать его как независимый экспорт верхнего уровня. Если вы просто втиснете их в статический класс без всякой причины, вы сломаете встряску дерева без всякой пользы для себя. - person Asad Saeeduddin; 27.01.2018
comment
Исходный вопрос описывает утилиту, которая не зависит ни от какого состояния. Это прямые статические функции. Вы говорите, что встряхивание дерева сломается, если вы не создадите экземпляр Util? - person Drenai; 27.01.2018
comment
Нет, я говорю, что встряхивание деревьев прекратится, если вы вообще сделаете class Util. Поскольку члены не имеют состояния (о чем я упоминал в своем ответе и на данный момент в двух разных комментариях), у вас вообще не должно быть класса. Вы должны экспортировать элементы напрямую, чтобы использовать встряску дерева. - person Asad Saeeduddin; 27.01.2018
comment
Как я могу обернуть ваши методы doSomething, doSomethingElse в пространство имен MyUtilsNS, чтобы избежать конфликта с другой библиотекой, в которой также есть doSomething, doSomethingElse? - person joedotnot; 20.07.2018
comment
@joedotnot Вы не можете, но при их импорте вы можете использовать их псевдонимы, как хотите. Например, вы можете импортировать их как import { doSomething as fooDoSomething } from "myfoomodule". - person Asad Saeeduddin; 20.07.2018
comment
Точно так же вы также можете просто использовать псевдоним всего импорта import * as MyFooModule from "myfoomodule" и использовать MyFooModules.doSomething, но имейте в виду, что такого рода вещи могут вызвать проблемы с встряхиванием дерева. - person Asad Saeeduddin; 20.07.2018

Альтернативный способ:

  1. Экспортируйте константы в файл utils.ts:

    export const doSomething = (val: string): any => {
      return val;
    };
    
    export const doSomethingElse = (val: string): any => {
      return val;
    };
    
  2. Импортируйте и используйте эти методы в основном файле *.ts:

    import { doSomething, doSomethingElse } from './util';
    ...
    let value1 = doSomething('abc');
    let value2 = doSomethingElse ('efg');
    
person Renat Gatin    schedule 21.05.2019
comment
Это лучше всего сработало для моей ситуации. Я смог import * as Util from './util'; и использовать функции как Util.doSomething('abc');. - person Kentaro; 21.09.2020

Или вы можете экспортировать как литерал объекта:

export const Util = {
    doSomething(val: string){ return val;},
    doSomethingElse(val: string{ return val;}
}
person Max Rahder    schedule 03.01.2019
comment
Это, вероятно, лучший способ сделать это. Я обычно создавал функции как const вверху файла, а затем использовал export const Util { doSomething, doSomethingElse } - person Drenai; 06.11.2019

Вы также можете создать класс util.ts с функцией экспорта

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

Теперь вы можете импортировать метод, как показано ниже, структура общих папок src > app > shared, я вызываю этот импорт внутри файла src > app > shelf > shelf.component.ts

import { formatDateOfBirth } from '../shared/utils/util';
public getFormattedDate(dob: string):string{
  return formatDateOfBirth(dob);
}
person vijay    schedule 02.04.2019