如何将TypeScript类拆分为多个文件?

时间:2014-05-26 19:43:55

标签: javascript typescript

我找到了很多例子,并尝试将模块分成几个文件。所以我得到那个,非常方便。但是出于同样的原因,有时候分割课程也很实际。假设我有几种方法,我不想将所有内容都塞进一个长文件中。

我正在寻找类似于C#中部分声明的内容。

11 个答案:

答案 0 :(得分:19)

你不能。

有一个功能请求要实现部分类,首先在CodePlex上,然后在GitHub上,但是on 2017-04-04它被声明为超出范围。给出了很多理由,主要的理由是他们希望尽可能避免偏离ES6:

  

TypeScript 已经具有太多特定于TS的类功能[...]添加另一个特定于TS的类功能是骆驼背上的另一根稻草,如果我们应该避免能够。 [...]因此,如果某些场景确实将其从公园中推出以添加部分课程,那么该场景应该能够通过TC39流程证明自己的合理性。

答案 1 :(得分:18)

我使用它(适用于打字稿2.2.2):

class BigClass implements BigClassPartOne, BigClassPartTwo {
    // only public members are accessible in the
    // class parts!
    constructor(public secret: string) { }

    // this is ugly-ish, but it works!
    methodOne = BigClassPartOne.prototype.methodOne;
    methodTwo = BigClassPartTwo.prototype.methodTwo;
}

class BigClassPartOne {
    methodOne(this: BigClass) {
        return this.methodTwo();
    }
}

class BigClassPartTwo {
    methodTwo(this: BigClass) {
        return this.secret;
    }
}

答案 2 :(得分:12)

Lately I use this pattern:

class BigClass {
    public getValue = getValue;
    public setValue = setValue;

    protected value = "a-value";
}

function getValue(this: BigClass) {
    return this.value;
}

function setValue(this: BigClass, value: string ) {
    this.value = value;
}

Often I move the functions in seperate files, for a clean and scalable setup!

答案 3 :(得分:3)

在转换使用' prototype'的大型旧多文件javascript类时,我使用简单的子类化。到多个打字稿文件:

bigclassbase.ts:

class BigClassBase {
    methodOne() {
        return 1;
    }

}
export { BigClassBase }

bigclass.ts:

import { BigClassBase } from './bigclassbase'

class BigClass extends BigClassBase {
    methodTwo() {
        return 2;
    }
}

您可以在任何其他打字稿文件中导入BigClass。

答案 4 :(得分:2)

您可以使用multi file namespaces

Validation.ts:

namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }
}

LettersOnlyValidator.ts(使用上面的StringValidator):

/// <reference path="Validation.ts" /> 
namespace Validation {
    const lettersRegexp = /^[A-Za-z]+$/;
    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }
}

Test.ts(同时使用上面的StringValidator和LettersOnlyValidator):

/// <reference path="Validation.ts" />
/// <reference path="LettersOnlyValidator.ts" />

// Some samples to try
let strings = ["Hello", "101"];

// Validators to use
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["Letters only"] = new Validation.LettersOnlyValidator();

答案 5 :(得分:1)

提议模式的修改版本。

// temp.ts contents
import {getValue, setValue} from "./temp2";

export class BigClass {
    // @ts-ignore - to ignore TS2564: Property 'getValue' has no initializer and is not definitely assigned in the constructor.
    public getValue:typeof getValue;

    // @ts-ignore - to ignore TS2564: Property 'setValue' has no initializer and is not definitely assigned in the constructor.
    public setValue:typeof setValue;
    protected value = "a-value";
}

BigClass.prototype.getValue = getValue;
BigClass.prototype.setValue = setValue;

//======================================================================
// temp2.ts contents
import { BigClass } from "./temp";

export function getValue(this: BigClass) {
    return this.value;
}

export function setValue(this: BigClass, value: string ) {
    this.value = value;
}

优点

  • 不会在类实例中创建额外的字段,因此没有开销:在构造、销毁过程中,不使用额外的内存。 typescript 中的字段声明仅用于此处的输入,它们不会在 Javascript 运行时中创建字段。
  • 智能还可以(在 Webstorm 中测试)

缺点

  • 需要ts-ignore
  • 比@Elmer 的答案更丑的语法

其他解的性质相同。

答案 6 :(得分:0)

我们可以使用prototypeInterface定义逐步扩展类方法:

import login from './login';
import staffMe from './staff-me';

interface StaffAPI {
  login(this: StaffAPI, args: LoginArgs): Promise<boolean>;
  staffsMe(this: StaffAPI): Promise<StaffsMeResponse>;
}

class StaffAPI {
  // class body
}

StaffAPI.prototype.login = login;
StaffAPI.prototype.staffsMe = staffsMe;

export default StaffAPI;

答案 7 :(得分:0)

为什么不只使用js已经附带的Function.call

class-a.ts

Class ClassA {
  bitten: false;

  constructor() {
    console.log("Bitten: ", this.bitten);
  }

  biteMe = () => biteMe.call(this);
}

和其他文件bite-me.ts

export function biteMe(this: ClassA) {
  // do some stuff
  // here this refers to ClassA.prototype

  this.bitten = true;

  console.log("Bitten: ", this.bitten);
}

//使用它

const state = new ClassA();
// Bitten: false

state.biteMe();
// Bitten: true

有关更多信息,请查看$setUnion

的定义

答案 8 :(得分:0)

我个人使用 @partial 装饰器作为一种简化的语法,可以帮助将单个类的功能划分为多个 ??? 类文件 ... https://github.com/mustafah/partials

答案 9 :(得分:0)

模块让你从另一个文件扩展一个打字稿类:

user.ts

export class User {
  name: string;
}

import './user-talk';

user-talk.ts

import { User } from './user';

class UserTalk {
  talk (this:User) {
    console.log(`${this.name} says relax`);
  }
}

User.prototype.sayHi = UserTalk.prototype.sayHi;

declare module './user' {
  interface User extends UserTalk { }
}

用法:

import { User } from './user';

const u = new User();
u.name = 'Frankie';
u.talk();
> Frankie says relax

如果你有很多方法,你可以试试这个:

// user.ts
export class User {
  static extend (cls:any) {
    for (const key of Object.getOwnPropertyNames(cls.prototype)) {
      if (key !== 'constructor') {
        this.prototype[key] = cls.prototype[key];
      }
    }
  }
  ...
}

// user-talk.ts
...
User.extend(UserTalk);

或者将子类添加到原型链中:

...
static extend (cls:any) {
  let prototype:any = this;
  while (true) {
    const next = prototype.prototype.__proto__;
    if (next === Object.prototype) break;
    prototype = next;
  }
  prototype.prototype.__proto__ = cls.prototype;
}

答案 10 :(得分:-1)

要添加到@Elmer的solution,我添加了以下内容,使其可以在单独的文件中工作。

some-function-service-helper.ts

import { SomeFunctionService } from "./some-function-service";

export function calculateValue1(this: SomeFunctionService) {
...
}

some-function-service.ts

import * as helper from './some-function-service-helper';

@Injectable({
    providedIn: 'root'
})
export class SomeFunctionService {

    calculateValue1 = helper.calculateValue1;  //  helper function delcaration used for getNewItem

    public getNewItem() {
        var one = this.calculateValue1();
    }