Typescript: 部分类

创建于 2014-08-29  ·  224评论  ·  资料来源: microsoft/TypeScript

添加对部分类的支持。 Mixins不一样,因为它是运行时实现的。 需要编译实现,在将 typescript 转换为 javascript 之前,部分类将合并为一个。

//FileA.ts
partial class ClassA
{      
    constructor(public name: string) {}
    public sayHello(): string { return "hi!"; }
}

//FileB.ts
partial class ClassA
{
   public sayBye(): string { return "by!"; }
}

将会:

partial class ClassA
{      
    constructor(public name: string) {}
    public sayHello(): string { return "hi!"; }
    public sayBye(): string { return "by!"; }
}
Out of Scope Suggestion

最有用的评论

部分类的一个用例是用于生成的代理类。 例如 WebAPI 或 SignalR 包装器。 能够使用自定义逻辑扩展生成的代理类会非常好。 特别是在为模型生成类时,能够将业务逻辑直接附加到从 api 返回的模型类会很好。

所有224条评论

我认为您也在模块上使用“部分”并帮助解决这里提出的这个问题。

https://github.com/Microsoft/TypeScript/issues/447

@disshishkov也许扩展方法就足够了:#9

您想将其用于哪种情况,现有解决方案如何达不到这一点?

请注意,这是在 C# 中实现的,以支持 WinForms 类型的编辑方案,其中自动生成的文件和用户编辑的文件属于同一类型; 我不确定这些情况是否适用于 JavaScript/TypeScript。

有些类可以有很多行号,只是为了更好地阅读,拆分为几个单独的类会有所帮助。 您可以按不同类型拆分,例如按逻辑(以防此逻辑无法移动到另一个类)、可见性(私有和公共)和其他。 如果分部类的组合可能出现问题(例如 2 个分部类相同的方法/变量声明),编译器应通知并抛出错误。

这真的不是很有说服力。 如果您的班级太大,由于其庞大的规模而无法在单个文件中轻松编辑,这是一种非常重要的设计气味(例如 http://programmers.stackexchange.com/questions/157482 中的评论)。 按不同类型/逻辑/可见性/等进行拆分可以由 IDE 或由单个文件中的组织处理。

值得讨论一下为什么您的类如此之大以至于无法导航(是因为导航工具应该更好吗?),以及是否有更好的方式该语言可以支持 _decomposing_ 一个类,而不仅仅是 _splitting_ 它。

就个人而言,我认为“部分类”应该存在,但表现得像合并在一起的模块。 我有一个带有模块的系统,尽管智能感知可以看到所有模块(应该如此),但包含它的实际 JS 仅在需要时加载。 我认为这同样适用于类 - 只加载所需的部分。 我还想创建一个函数,并使用一个类来进一步扩展它。 目前,您只能使用模块执行此操作。

部分类的一个用例是用于生成的代理类。 例如 WebAPI 或 SignalR 包装器。 能够使用自定义逻辑扩展生成的代理类会非常好。 特别是在为模型生成类时,能够将业务逻辑直接附加到从 api 返回的模型类会很好。

+1 kvantetore。

用例与.net完全相同; 生成了类的一部分(在我们的例子中,来自 Avro 模式)并且您想要添加额外的帮助程序代码来处理生成的类。

我喜欢这个建议。 我想要有部分类,以便将形成我的“数据层次结构”的类的属性/属性与可以在其他几个文件中拆分的方法分开,这些类可以收集在一个文件中。 它会让代码一目了然,更容易理解。

我的数据层次结构文件

class A {
  x: number;
  y: number;
  z: number;
}

class B extends A {
  value: string;
  flag1: boolean;
  flag2: boolean;
}

包含 A 类方法的文件

class A {
  constructor(x: number, y: number, z: number) {
    this.x = x;
    this.y = y;
    this.z = z;
  }
  method1(...) { ... }
  ...
  methodN(...) { ... }
}

包含 B 类方法的文件

class B extends A {
  constructor(x: number, y: number, z: number, value: string) {
    super(x, y, z);
    this.value = value;
    this.flag1 = false;
    this.flag2 = false;
  }
  method1(...) { ... }
  ...
  methodN(...) { ... }
}

来自我的 +1。 我想使用 tt 模板来生成 Typescript 类,但将它们添加到一个单独的文件中,该文件不会被模板生成替换。

+1 这将真正帮助我处理我需要扩展的自动生成的类

Partial Class 真的很好,但是拥有它没有意义。 它表明你有一个设计问题。 编程的经验法则是保持简单愚蠢(KISS),无论您使用什么语言,都是将大类分解为较小的类 - 通过以下任一方式:1)将脚本拆分为类并调用它们(其他类也可以调用较小的类,而不是重新发明轮子),或 2)分解并转换为抽象/接口/继承/虚拟等或多态性。

假设您有一辆载有一切的 Vehicle。 部分类没有意义,它在这里引入了复杂性和开销,而这样做更有意义。 创建一个 Engine 类、Tranny 类、Drivetrain 类、Door 类和 Tyre 类作为单独的类并将脚本移到它们上面,调用时仍然可以在 Vehicle 类中定义一个 Vehicle。 它减少了冗长的脚本和脚本的复杂性。 您可能会发现到处都有可以通过 Door 类简化的 Door 脚本。 Interface/Abstract/Inheritance/Virtual 可用于更改 Vehicle 类中某些脚本上的 Door 类定义。

您也更有可能以这种方式拥有更少的开发时间。 我曾经有过使用大量部分类的 ASP.NET C# 博客。 我一直在努力解决它,因为有太多的部分类,你不知道它们在哪里。 这有点像在编程中处理 GOTO 逻辑。 坏坏!! 我从来没有能够成功地为错误修复创建补丁,也无法自定义脚本,因为它被埋在一堆部分类中(一些重命名的措辞也是如此)。

只是说它是我心中的 1 美分想法。

@fletchsod-developer:有些情况可以通过继承正确处理,但不是全部。 一些开发人员可能会滥用部分类,但不是全部。 在某些情况下,我发现部分类非常非常有用,但如果您不喜欢它们,则不必使用它们。

@@basarat建议将#9不工作?

// File1.ts
class Dog { 
 ...
}

// File2.ts
extends class Dog {
  woof() { /* ... */ }
}

@NoelAbrahams ,您是否能够访问文件中 file1 的定义,但反之亦然? 只要与包含顺序无关,这对我来说就可以了。

我真的希望你们将部分类视为 TS 的 C#...对我来说唯一的原因是代码生成,这是 C# 部分类背后的主要原因...我们目前正在做很多 TS 代码生成,我们期望做的越来越多......目前我们不得不依赖“//

+1 - 真的可以用它来为自动生成的类添加功能; 迄今为止,没有其他我能想到或读到的优雅解决方案......

+1 - 代码生成的类。 C#/Java 对象序列化到客户端

合并生成的类也需要这个!

这将是一个非常有用的功能,可以将生成的代码与非生成的代码简单合并。

+1

+1 - 对于部分生成的类,我们也需要它,它比继承更优雅,继承会发出大量不需要的代码。

+1

再次遇到此限制 - 请添加此功能! :+1:

+1

+1

+1

+1

人们随机+1 这不会继续前进。

到目前为止的用例是:

  • 我有跨越多个文件的非常大的类。 @RyanCavanaugh表示,代码复杂且不足以保证实现的复杂性,这可能是一个主要的设计问题。
  • 它喜欢他们。
  • 另一个论点似乎是 C# 有它们。
  • 另一个论点是围绕从其他语言生成的代码。

第二个和第三个用例并不引人注目,第四个,我怀疑需要在一定程度上阐述如何交付 #9 不会满足非常相似的要求,甚至是装饰器 (#2249)。

看起来#9 确实可以完成同样的事情并且更加通用(因为您可以扩展自己的类以外的类)。 但是将类内容放在两个文件中可能是合理的(可能是因为一个是手写的,另一个由模板生成),并且说这两个文件都定义了具有同等重要性的类的基本成员,并且不需要一个文件“扩展”了另一个中定义的类。

这几乎是存在的差异,但在某些情况下对某些人来说可能很重要。

由于所述原因,我不想偏袒类,但在模块上,恕我直言是有道理的。

https://github.com/Microsoft/TypeScript/issues/447

分部类对于专门化用例非常有用。 它不违反任何 OOP 模式,而是一种排列代码文档的方式,它提供:

  1. 能够在多个文件中拆分类/类型定义。 对于庞大的代码文件,它是可维护性++特性。
  2. 编译器/构建系统在编译时利用条件链接的机会。 类比 MSBuild,C# 中的具体用例:DBML、设计器类以及更多奇特的东西,如https://github.com/dotnet/corefx/pull/2045/files。
  3. 固有保护,因此两个(或多个)开发人员在代码签入期间不会遇到彼此。 冲突解决! :)
  4. 让您在主分部类中生成代码,然后为自定义重载创建另一个分部。 完美运行!

我相信将业务逻辑层和数据层分离到单独的类中,并且我主要在这些层中使用静态方法。 我真的不明白它怎么会有更多的代码和更少的可维护性。

扩展方法是受 OO 模式影响的核心语言特性,将在编译时处理,部分类处理要在预编译阶段拼接的文档/代码布局。 尽管部分类、抽象类和扩展方法有相似之处,但还是有明显的区别。

:+1: 将无害的“部分类”引入 TypeScript。

我的部分类用例用于代码生成——我的团队需要能够在一个文件中自动生成部分类,并在另一个文件中手动添加自定义方法和属性。 我有点困惑为什么@RyanCavanaugh是“不确定这些情况是否适用于 JavaScript/TypeScript”,因为这个用例与选择的语言无关。

装饰器和扩展方法都没有像部分类那样优雅地解决代码生成问题,并且每个都有大量额外的复杂性。

+1

+1

+1 用于代码生成目的。

在 C# 环境中,将 C# 类的转译器集成到 TypeScript 类将不再需要在服务器端和客户端之间保留两个不同的类定义,因为客户端(即 TypeScript 类)将自动生成,并且部分类这个问题所要求的将允许在需要时进行自定义,同时仍然使用原生 TypeScript 进行开发。

+1 代码生成场景

+1 对代码生成非常有帮助

为什么不使用继承来生成代码?

继承更混乱,开销更大。

2015 年 8 月 10 日星期一上午 10:09 Gorgi Kosev [email protected]写道:

为什么不使用继承来生成代码?


直接回复此邮件或在 GitHub 上查看
https://github.com/Microsoft/TypeScript/issues/563#issuecomment -129468291
.

继承会产生无用的名称耦合

继承不那么棒,因为它:

  1. 不必要地加深原型链并减慢实例化,
    虽然这对大多数应用程序来说没什么大不了的,但可能除了游戏之外的所有应用程序;
  2. 由于缺乏抽象和覆盖,要么失去一些类型安全,要么
    引入了一些反向模式的需要,比如在两者之间进行转换
    类型;
  3. 总体上令人困惑,因为有一个基类传达的想法是
    它可以被其他类扩展,这在 codegen 中很少出现

并不是说打字稿必须有部分类来支持代码生成,只是
部分类比继承或
作品。

@JoshMcCullough JS 中的继承开销很小,我看不出它比部分类有多么混乱:使用这些类,您可以将一个类拆分为 10 个文件,并在所有地方追逐您的方法。

@yahiko00我们在这里谈论什么样的“无用的名称耦合”? 您是否提到了获得下面第 2 名所需要做的事情(对扩展类的名称进行硬编码)?

@hdachev

  1. 有一些开销,但它非常小- 只有在您做的事情直接转换为几条机器指令时才会明显
  2. 好点 - 当您必须从其他生成的类中引用生成的类时,您不会获得扩展类。
  3. 这些类确实是为了扩展 - 否则你可以生成它们并完成它,对吧?

AFAIK 这不在 ES7+ 雷达上,是吗? 那可能有问题...

在任何情况下,将额外的东西附加到现有类的原型在 JavaScript 中是非常微不足道的,而且一点也不罕见,因此为此使用语法可能是个好主意......

在 TS 中很简单,但幕后的 JS 会加倍
“原型设计”,如果您为所有生成的数据使用基类
对象。 可能不会对性能造成严重影响,除非您有大量
数据对象,但当我们知道“部分
类”是可能的。

2015 年 8 月 10 日星期一上午 11:03 Gorgi Kosev [email protected]
写道:

@JoshMcCullough https://github.com/JoshMcCullough继承开销
在 JS 中是最小的,我看不出它比部分类更混乱:
有了这些你可以将一个班级分成 10 个文件并追逐你的
方法无处不在。

@yahiko00 https://github.com/yahiko00什么样的“没用的名字
耦合“我们在这里谈论的是什么?你指的是你需要的东西
怎么做才能得到下面的第 2 名(硬编码扩展类的名称)?

class MyClass 扩展 GeneratedMyClass { ... }

@hdachev https://github.com/hdachev

1.

有一些开销,但它非常小
https://jsperf.com/prototype-chain-vs-direct-calls - 仅引人注意
如果你正在做的事情直接转化为几台机器
指示
2.

好点 - 当你必须时,你不会得到扩展课程
从其他生成的类中引用生成的类。
3.

这些课程确实是为了扩展 - 否则你可以
生成它们并完成它,对吧?

AFAIK 这不在 ES7+ 雷达上,是吗?

无论如何,将额外的东西附加到现有类的原型上
在 JavaScript 中非常简单而且并不罕见,所以它可能是一个
有语法的好主意......


直接回复此邮件或在 GitHub 上查看
https://github.com/Microsoft/TypeScript/issues/563#issuecomment -129483174
.

@Davidhanson90该文件中的类为零。 你是想把这个发到另一个帖子里吗?

我会发布到正确的线程上。 https://github.com/Microsoft/TypeScript/issues/447

+1

+1

+100

+1

+1

+1 用于代码生成。
我一直在使用 angularjs 和 webapi,我想制作一个工具,它基本上可以从我的 c# 对象和服务中创建自动 JS 定义。 我希望能够扩展这些类而无需编辑“脚手架”JS 定义。 我看到其他一些人正在请求这个,我们似乎有类似的用例。

+1 代码生成

+1 代码生成,angular 有很多样板代码,我们已经做了很多生成,但是使用部分类我们可以做更多。

再次为代码生成 +1。 尝试在另一个文件中扩展类充其量是混乱的。

@RyanCavanaugh ,需要什么才能摆脱“+1”模式并朝着富有成效的方向发展?

-1 以下语法更适合混合:#2919

不知道为什么我们不能同时拥有部分类和混合; 两个完全不相关的功能。

+1

这在生成代码时会很好,但您不想修改它以向生成的代码添加内容。

+1

我有一个提案应该满足这两个用例:

  1. 您想在不同的地方编写自己的类的方法。
  2. 您想向其他人的类添加新方法,例如内置方法。

对于 (2),通常您只需使用::运算符来获取中缀语法。

但是如果你想让一个旧的类成为新接口的一部分,或者如果你想动态调度,你将需要实际修改原型。

interface ITimes {
    times(n: number): number
}

Array implements ITimes {
    times(n: number): number {
        return this.length * n
    }
}

// The compiler should check that all methods of ITimes and IOther are implemented.
Number implements ITimes, IOther {
    times(n: number): number {
        return this * n
    }

    other(): void {}
}

// The old types should typecheck with the new interface.
const x: ITimes = true ? [] : 0
x.times(3)

// The interface list can be empty. This essentially gives you partial classes.
MyClass implements {
    anotherMethod(): void {}
}

(在示例中,我使用字符串方法名称,但由于这些是内置类型,因此一旦可以对它们进行类型检查,使用符号会更好。)

这对真正的部分类的一个改进是该类有一个单一的定义,其他地方只是扩展它。 这意味着有一个明确的位置可以从中导入类并使转换为 JS 更容易。

:+1: 我也很想看到部分课程。

此功能的状态如何?

此用例例如:

我有一个Math包,它定义了一个类Set ,方法有Set#add , 'Set#remove'

// math.ts
export partial class Set {
  add(){}
  remove(){}
}

我有一个可选的重的Relational包,它定义了类RelationTuple

这个Relational包还会添加一个Set#product方法。

// relational.ts
///<reference path="./../math/tsd.d.ts"/>
partial class Set {
  product(){}
}

export class Relation(){}
export class Tuple(){}

部分类将允许我以更灵活的方式组合类。 如果我不想使用沉重的relational包,我仍然可以使用基本的 Set 功能。 其他partial类只会进来并为该类添加额外的功能。

在这种情况下,我正在挠头做一些不使用部分的事情,它将有一个很好的 API。

我所能提供的只是一些存储库模式。

// Without partials

// base

export class Base {
    static registerOperation(opName, method){
        this.prototype[opName] = method;
    }
    operation(name, ...args){
        return this[name].apply(this, args);
    }
}

// math.ts
import {Base} from './base';
class Set extends Base{
    // Define the methods here
    add(){}
    remove(){}
}

// Or here
Set.registerOperation("add", function(...){});
Set.registerOperation("remove", function(...){});

// relational.ts
import {Set} from './../math/math';

Set.registerOperation("product", function(...){});

// app.ts

import {Set} from 'math';

var set = new Set();
set.add // compiler error
set.remove // compiler error
set.product // compiler error

// have to use something like
set.operation("add", args);
// or
(<any>set).add(arg);

+1 我正在使用 t4 通过 WebApi 生成类和代理。 我认为自动生成在打字稿中大量使用,当涉及到自动生成时,部分类是必要的!

拆分同一类的方面会很棒,尤其是在 React 中
+1

+1 代码生成和“恰到好处的分离”,在纯可重用数据对象的情况下,具有客户端特定的属性,用于类似的验证,在类上定义但在单独的源代码中维护。

+1 用于部分类的代码生成,并在单独的文件中为这些类手动编码附加成员。

+1

+1 我在我们的 js api 服务中有大量方法基础,最好将它们拆分为文件,这样可以轻松理解每个方法。

api 服务,如fb (facebook)gq (google analytics) ,您可以在其中获得一个全局类或对象,您可以在整个开发过程中使用它们。

+1

这个功能对我们来说也是一个很大的优势。

我们开发了一个中间件,所有类型的客户端都可以通过它连接到我们的服务器并与之通信。

我们根据服务器公开的内容生成一些客户端代码。

到目前为止,一切正常。 但是现在,我们希望能够传输异构的对象集合(但具有相同的基类)。 传输的对象是基于服务器 API 生成的代码的一部分。

为了能够使用继承的力量,在这种情况下抽象方法是关键。 但是我们的开发人员不会向生成的代码添加方法,我想每个人都知道原因;)

据我了解(我是 C# 开发人员),此处提出的解决方案(https://github.com/Microsoft/TypeScript/issues/9)不允许我们这样做。

所以,部分类对我们来说是完美的。 我们会将类生成为部分类,如果开发人员需要添加逻辑或方法,他们只需要在他们想要的任何地方编写其他部分。

+1

+1 对代码生成非常有帮助

我想知道模块扩充是否基本上否定了将此作为特定功能的需要。

如果你有一个生成的类,那么你应该能够做类似的事情......

import {MyClass} from "./MyClass.generated"

MyClass.prototype.partialMethod1 = function() {
  return true;
}
MyClass.prototype.partialMethod2 = function(abc: string) {
  this.doSomething(abc);
}

declare module './MyClass.generated' {
  interface MyClass {
    partialMethod1(): boolean;
    partialMethod2(abc: string): void;
  }
}

@disshishkov这看起来是在

我同意象船。 分部类的手工制作部分应尽可能松散耦合(在 TS 中的设计时)与生成部分的耦合。

@david-driscoll 的建议适用于许多情况。 但是,据我所知,原型无法访问内部变量。 这限制了这种方法在代码生成上下文中的有用性,在这种上下文中,您希望生成类的核心部分,然后使用自定义代码对其进行扩充。

+1

@david-driscoll 看起来是对这个功能进行脱糖的好方法。 (需要添加访问私有/受保护属性的能力)。 想知道多个部分类声明会发生什么? 这些的相互可见性是什么?

++ 1 在尝试扩展我的自动生成模型时,缺少部分真的很伤害我..

我认为这里唯一的东西基本上是@david-driscoll 提出的——你可以声明新方法(将放在原型上)和新的 _non-initialized_ 属性(没有代码生成),但不能声明新的初始化属性(因为这些对构造函数代码生成有副作用)。

被否决了,请原谅我的法语,部分类是一种愚蠢的尝试,将 OOP 中不可避免的神类分成多个文件,以便它们更易于管理(尽管仍然是神类)

有了面向对象编程,你们没有未来(去过那里,知道我在说什么)

来到 FP,我们有 cookie 和一种无需单个类即可编写程序的方法,就像这样

所以我们基本上已经通过interface A { method(): void } A.prototype.method = function() { };允许这样做

自行车棚的一件事是关键字partial 。 一个简短的历史小插曲:在 C# 中, partial class最初将是extension class (除了一个声明之外,您将其放在所有声明中),但是对于哪些声明将是extension以及哪个声明将是非扩展声明。 相反,您必须将修饰符partial放在 _all_ 类上。

这在 TypeScript 中_不是_; 恰恰相反。 在这里,只有一个类(我们称之为“_primary_ 声明”)可能有构造函数/初始化成员字段; 主声明没有任何新的修饰符。 每个其他声明(让我们称它们为“_extension_ 声明”)可能只有静态、方法和未初始化的字段,并且您_需要_在它们上有一些修饰符以表明它们不是主要的。

目前最好的猜测是

class Foo {
  x = 6; // only legal to initialize here
  constructor() { } // only legal to have constructor here
  someMethod() { }
}

// vvvvvvvvv thoughts?
   extension class Foo {
     someOtherMethod() {
     }
   }

:sparkles: :bike: :house:: :sparkles:

Bikeshedding 与否,这听起来像#311一样糟糕,因为可能会干扰未来的 ECMAScript 标准而被弃用。 为什么这值得考虑,但适当的 mixin 支持却不是?

使用关键字extension扩展方法冲突? 或者这是否会完全否定扩展方法?

@kitsonk我认为 mixin 提案有更多未解决的问题。 这里的部分类提案只是对 TypeScript 中已经允许的东西的编码,只是添加了一些语法糖(这个功能实际上可以作为对我们已经拥有的东西的语法重新映射来完成)。

@Elephant-Vessel 如果发生部分类,我认为不会发生扩展方法。 考虑到我们的约束,类是扩展方法唯一有意义的地方,并且提议的 ES7+ 绑定运算符是一种更好的方式来硬塞类似扩展的语法。

@RyanCavanaugh :对我来说,要求一个班级是主要的而其他班级不是,这似乎有点限制。 如果您想对代码进行分区,以便一个文件包含一个类的所有方法,另一个包含所有属性,那么这两个文件似乎都不是主要的,为什么要被迫选择? 在它们的重要性都相同的地方拥有部分并由编译器合并不是更干净吗?

@RyanCavanaugh ...我会以与c#完全相同的方式来做...它非常适合代码生成...我相信这是该功能旨在在C#中解决的主要问题...虽然我的记忆很模糊... 从来没有任何问题,它已经存在多年了,并且经过了实战考验......

如果部分/扩展类无法初始化字段,我认为支持我们从 C# 中知道的部分方法之类的东西会更加整洁,基本上是特定于部分类的轻量级契约。 所以像:

public partial class MyGeneratedClass
 {
     partial void Initialize();
     public constructor()
     {
          //...
         this.Initialize();
    }
 }

 public partial class MyGeneratedClass
 {
     partial void Initialize()  { //... }
 }

通过使partial/extends通常可选但需要使用部分方法,可以很容易地(?)解决能够部分化/扩展第三方类的需要。

我认为这可以为我们在这里想要的概念带来一些简洁的表现力和操作力。

那些正在寻找 mixin 的人。

考虑对象初始化提议,通过它(和流程分析)混合可以优雅地、自然地、惯用地完成,就 JavaScript 而言:

function enableBeingPositioned<a>(
   // hypothetical syntax
   something: a /* <-- before type */ => a & { x: number; y: number; } /* <-- after type */
): void { 
   something.x = 0;
   something.y = 0;
}
let value = {};
value.x; // <-- should not typecheck
enableBeingPositioned(value);
value.x; // <-- should typecheck

Java 等语言不提供部分类/结构。 它是 C# 的一个小众特性。 完全模仿 C#“部分类/结构”概念是最好的方法。
在预编译步骤中,TS 编译器可以做的第一件事是拼接内存中的部分代码块,然后转到常规编译流水线路线。 这将足以获得 TypeScript 中部分类功能的v1.0.0-preview1.0000的资格。
C# 提供的功能之外的任何东西都可以在以后的版本中引入,届时该功能将发展并超过其试用版/预览版。 角落案例和类似的晦涩的东西可以一次一个地单独讨论,我们可以稍后担心适合和完成...... IMO。

我也同意完全按照 c# 的方式做部分和扩展类
就语法和语义而言,这是否是最好的方法,两者都有效
非常适合他们各自的用例。 部分课程提高了
生成代码的可用性。 扩展方法提高可用性
操作接口的静态方法、指定的泛型和第三个
派对类型。 两者都非常酷,但请记住它们不是
同样的功能,我在这里说这个是因为上面建议的语法。

扩展方法将允许一个人这样做(sry 缺乏格式,
在手机上打字):

扩展我的类型[] {
somethingSpecificToMyType() { ... }
}

扩展奇怪的第三方数据结构{
同样在这里() { ... }
}

除其他事项外,例如能够使用下划线等库
没有 cruft,这基本上意味着获得
扩展内置类型而不实际污染它们。

如此简短 - 让我们不要将两者视为一回事,它们都非常
很酷但不是一回事。 我个人很想在我们的
语。

顺便说一句,作为旁注,我想很多人都对
代码生成并准备向大家解释它没有位置
在 javascript 中,因为有更多惯用的方法来实现相同的目标。
代码生成有两种方式在某些方面有很大帮助
项目,比如我现在正在做的项目。

  • 在对性能敏感的项目中,例如游戏,您只需在其中执行
    通过有用的工作最大化您的 CPU 预算的一切,codegen 有很大帮助
    生成易于推理且高度可优化的代码
    / jits 非常好的单态代码。 例如,在一个
    实体/组件游戏引擎,生成的代码可以帮助处理大量的东西
    像非常快速的样板代码,用于将组件粘在一起,事件
    派遣等
  • 在大型商业应用程序中,生成的代码有助于从
    类型系统,例如通过发出非常具体的方法
    数据库查询等的签名,最大限度地延长了编译时间
    检查,帮助大量重构,还大大简化了调试
    因为它允许您逐步执行非常简单的编排代码。
  • 最大的问题是当你让一些组件保持同步时
    多语言环境,例如与消息相关的东西
    像协议缓冲区,或者只是 json 消息接口等。

作为另一个侧面节点,让任何想知道什么部分的人受益
类与代码生成有关,即保留生成部分的价值
一个类到一个单独的文件来自源代码控制要求 -
生成的东西通常是一个快速变化的构建工件,你
不希望它在您的回购中提交。

我喜欢根据这个概念的一个众所周知的和经过验证的模型来实现这个想法,就像 C# 一样。 “模仿”有一些负面含义,但如果做得巧妙,它具有重大价值。 另一方面,“智能”部分是要注意不同的情况和限制,所以如果 TypeScript 的部分看起来不像 C# 的部分,我不会抗议。

@Elephant-Vessel,我同意它不必是 C# 部分的同上副本,一般设计可以首先围绕 TypeScript / JavaScript 风格进行布局,同时从 C# 部分中获得最大的灵感。 我的建议是将“注册partial关键字”和“拼接部分”作为第一步,并将其作为实验/预览功能发布(因此消费者不要开始在生产代码中依赖它)马上结束)。 之后,根据社区的响应,改进该功能,直到它准备就绪并进行 RTM 处理。 如果我们事先担心各种棘手的问题和场景,那么很可能会进一步拖延问题。

+1 - 用于扩展和维护生成的对象。

+1 用于维护生成的代码

我创建了 polyfill 并划分了我的大班。

将类定义为接口。

export class C {
  constructor() {
  }
}
export interface C {
  m(): void;
}

实现类成员。

export default class extends C {
  m(): void {
  }
}

合并实现。

import {C} from './core';
import m from './member/m';

compose(C, m);
export {C}
import {assign} from './assign';
import {concat} from './concat';

export function compose<T extends new (...args: any[]) => any>(target: T, ...sources: T[]): T {
  return concat([target], sources)
    .reduce((b, d) => {
      void assign(b.prototype, d.prototype);
      for (const p in d) if (d.hasOwnProperty(p)) b[p] = d[p];
      return b;
    });
}

https://github.com/falsandtru/spica/commit/a6ff30da5319db5f25f703a29da48fc0f7dbe2fe

我认为这是一个糟糕的想法,有一个特定的原因:它会使已经很复杂的全局、环境、外部、命名空间和脆弱的声明顺序依赖继承问题的规则变得更糟。 这不是 C#,名称解析和成员声明非常不同。

也许使用对象或命名空间而不是类,如果您真的需要这样做,可以使用揭示模块模式。 否则你的班级可能太大了。

也可以使用装饰器来实现生成代码和手写代码之间的关联。

你有其他解决方案吗?

我也很想看到这个添加到 TS 中

+1 用于代码生成目的(来自 WCF 服务引用的 DTO,带有额外的部分类定义)

+1 用于代码生成目的。 我的用例是:我有 React 组件,其render()函数是通过react-templates 在外部

使用partial类,我可以对此类函数与主类( Component )进行类型检查。 如果没有分部类,我唯一​​能做的就是将函数绑定到主类并希望最好。

在下一个 TS 2.0 中,我认为this类型功能可能会涵盖某些代码生成案例。

例如在我之前描述的情况下,而不是

partial class MyComponent extends React.Component<any,any> {
    render() {
        ...
    }
}

我可以写

function render<this extends MyComponent>()
        ...
}
MyComponent.prototype.render = render;

+1 作为开发人员,我想要部分类,以便多个模板可以生成/修改分布在多个文件中的同一个类。

我的评论专门针对部分类,而不是混入。 两者有本质的不同。 部分类是关于分解物理代码,mixin 是关于将逻辑行为分解为可重用的特征,在类型和值级别丰富其他对象。
我认为部分类对于 TypeScript 来说不是一个好主意。 另一方面,正如@aleksey-bykov 所指出的,mixin 是一个好主意,它提供了增强的表现力和与 TypeScript 的类型系统和 JavaScript 习语的非常好的啮合

@wendellm考虑到 ES 模块是物理的,你能想到一种干净的方法来做到这一点。 分部类工作良好,并且在像 C# 这样的语言中很有意义,其中模块是逻辑的而不是物理的。 从 CLR 的角度来看,命名空间不存在,只是类名中可以有点(来源对@ahejlsberg 的采访)

+1 我需要部分课程!

我们可以扩展接口吗? 接口也可以有一些实现的功能,就像Swift一样:

interface Rect {
    x: number
    y: number
}

extension Rect {
    area() => this.x * this.y
}

迅捷版:

protocol Rect {
    var x: Float {get}
    var y: Float {get}
}
extension Rect {
    func area() -> Float {
        return self.x * self.y
    }
}

+1

代码生成和部分类齐头并进。

对于本质上美化的#include指令,继承是一个糟糕的解决方案。

以 Angular 2 为例。 它不会从父类

@tsvetomir这是一个 Angular 问题,而不是一个 TypeScript 问题。

对于本质上美化的 #include 指令,继承是一个糟糕的解决方案

是的继承是一个糟糕的解决方案,但问题是首先使用类。 他们有自己的位置,但非常有限。 与其他语言中的类相比,JavaScript 类非常薄弱且缺乏表现力。

打字稿不是一种“角度”语言......从来都不是

在2016年7月23日,在下午9点46分,Aluan哈达德< [email protected] [email protected] >中写道:

@tsvet omirhttps://github.com/tsvetomir这是一个 Angular 问题,而不是一个 TypeScript 问题。

对于本质上美化的 #include 指令,继承是一个糟糕的解决方案

是的继承是一个糟糕的解决方案,但问题是首先使用类。 他们有自己的位置,但非常有限。 与其他语言中的类相比,JavaScript 类非常薄弱且缺乏表现力。

您收到此消息是因为您发表了评论。
直接回复本邮件,在Gi tHub上查看阅读https://github.com/notifications/unsubscribe-auth/AJPCIh7n2_0dt00kw- XJv7tc9LB0tPsIks5qYtH4gaJpZM4CcixK。

我不认为这个问题是 Angular 特有的。 这是部分类可能有所帮助的特殊情况。

该请求源于过去使用 C# 的经验以及缺乏熟悉的功能。 这种比较是不可避免的,因为 TypeScript没有努力与 .NET 保持距离。 其用户期望某种形式的特征奇偶校验。

该请求源于过去使用 C# 的经验以及缺乏熟悉的功能。 这种比较是不可避免的,因为 TypeScript 没有努力与 .NET 保持距离。 其用户期望某种形式的特征奇偶校验。

@tsvetomir作为长期的 .NET 开发人员和热情的 C# 程序员,我从根本上不同意。

您引用的文章不具有权威性,也不反映 TypeScript 团队的任何官方材料。

此外,它直接与@ahejlsberg在众多演讲、采访和帖子中所述的 TypeScript 设计理念相矛盾。

此外,引用的文章的观点反映了对 TypeScript 本质的根本误解。
具有讽刺意味的是,C# 与 TypeScript 的共同点实际上与它与 JavaScript 的共同点相同。
这些共性不是基于类的编程,而是诸如闭包和高阶函数之类的构造。

无论是否使用 C#,我们都需要部分类来帮助 TypeScript 更接近 Javascript 的原型特性。

@yahiko00
TypeScript 已经拥有 JavaScript 的所有原型特性。
它是一个超集。

TypeScript 中部分类的概念存在几个问题,包括

  1. 与 C# 不同,TypeScript (JavaScript) 类定义是命令式的,而不是声明式的。 它们看起来是声明性的,但实际上不是。 这意味着它们取决于确定性的执行顺序。
  2. ECMAScript 模块系统基于导入物理而非逻辑代码单元。
    例如,假设我有

_app/my-class-part-1.ts_

TypeScript export partial class MyClass { firstName = "John"; lastName = "Smith"; }


_app/my-class-part-2.ts_

TypeScript export partial class MyClass { fullName = this.firstName + ' ' + this.lastName; }

我怎样才能导入这个类? 由于我无法从任一模块导入,让我们想象一下 TypeScript 中的一个假设抽象,它允许我编写
_app/main.ts_

TypeScript import { MyClass } from './my-class';

这意味着什么? 即使 TypeScript 编译器可以推断 _app/my-class-part-1.ts_ 必须在 _app/my-class-part-2.ts_ 之前加载,它也不能使单个部分的导入无效,也不能确保它们由异步模块加载器(例如 RequireJS 或最终将在浏览器中实现的内容)以正确的顺序导入。

部分类的整个概念从根本上与 ECMAScript 模块系统不一致。

更新:它需要执行任意复杂的依赖推断并发出一些非常奇怪的 JavaScript。

TypeScript 已经拥有 JavaScript 的所有原型特性。
它是一个超集。

我应该更好地表达自己。 当然,我们都知道 TypeScript 是 JavaScript 的超集。 但我想说部分类将帮助 TypeScript 类更接近 JS 原型。 目前,我们可以只拥有“静态”和不可扩展的类,而通过原型方法,我们可以扩展类函数。

导入部分类会扩展当前的 ES6 语法,我同意。 我们可以想象这样的事情:

import { MyClass } from ['app/my-class-part-1', 'app/my-class-part-2'];

TypeScript 类基于 ECMAScript 类,因此后者缺乏表现力。 考虑使用函数、模块、“命名空间”或普通对象来完成您的需要。

函数是我们想要避免使用类的概念。
模块或命名空间带来了简单的可扩展性,并且与 TypeScript 的类具有不同的表现力。 此外,命名空间或模块不能被实例化。 它们与类的目的不同。

@aluanhaddad我明白你对模块的意思。 一种可能的解决方案是仅允许其中一个文件包含export partial class而其余文件仅包含partial class定义。 你从它导出的地方导入它。 从你的例子:

_app/my-class.ts_

export partial class MyClass {
    firstName = "John";
    lastName = "Smith";
}

_app/my-class.part.ts_

partial class MyClass {
    get fullName(): string {
        return this.firstName + ' ' + this.lastName;
    }
}

_app/main.ts_

import { MyClass } from './my-class';

缺少的是让编译器知道在哪里定位部件的语法。 这不是 C# 的问题,您可以一次处理所有文件。 这可能是一种特殊的语法,如用于声明 merging 的语法。

部分类不需要允许任意定义。 例如,它们可以仅限于方法、属性和构造函数。 这使得执行顺序变得无关紧要,并允许编译器在成员重复时抛出错误。

我不明白为什么模块增强对这些场景无效。 使用 Rxjs5 对我们来说效果很好。

您只需创建基类,然后通过代码生成,在基类之上生成您需要的所有增强方法。 生成的代码是否漂亮并不重要,没有人应该编写它。

它是部分类的完美替代品吗? 我想不会,但除非 ECMAScript 决定 JavaScript 需要它们,否则我不会看到部分类发生。 部分类如何在外部模块之间链接在一起的语义让我很头疼。

@david-driscoll 为了让它变得更好,添加的方法可以声明一个this:参数,以进行更强大的类型检查。

在引用的模块增强示例中:

// observable.ts stays the same
// map.ts
import { Observable } from "./observable";
declare module "./observable" {
    interface Observable<T> {
        map<U>(f: (x: T) => U): Observable<U>;
    }
}
Observable.prototype.map = function (this: Observable, f) {
    // here "this" has the shape of the "Observable" class
}

是的。 Rxjs 还没有安静地使用它,因为它是 2.0 的特性,而 2.0 还没有发布。 稍后它在我的命中列表中。

我明白你对模块的意思。 一种可能的解决方案是仅允许其中一个文件导出部分类,而其余文件仅包含部分类定义。 你从它导出的地方导入它。 从你的例子:

_app/my-class.ts_

export partial class MyClass {
    firstName = "John";
    lastName = "Smith";
}

应用程序/我的类.part.ts

partial class MyClass {
    get fullName(): string {
        return this.firstName + ' ' + this.lastName;
    }
}

我喜欢这个句法概念,但问题是你刚刚引入了一个新的 _kind_ 源文件,它作为一种隐式模块使用,看起来像一个脚本,必须以特定方式加载。

缺少的是让编译器知道在哪里定位部件的语法。 这不是 C# 的问题,您可以一次处理所有文件。 这可能是一种特殊的语法,用于声明合并。

声明合并适用于 _declarations_,而不是源文件。

部分类不需要允许任意定义。 例如,它们可以仅限于方法、属性和构造函数。 这使得执行顺序变得无关紧要,并允许编译器在成员重复时抛出错误。

所有这些_都_通常依赖于顺序。

编辑:也就是说,定义它们会修改类。

可能有人已经提到了这一点,但另一个有用的情况是,当您从某个代码生成器生成部分类时,您希望直接在您的实现中手动添加更多代码。
你真的不想做混合或派生类。
它仍然是一类——只是一部分是自动生成的,另一部分是手动生成的。

顺便说一句:如果有人需要从 C# 类生成 TS 类型,您可以检查TypeScriptBuilder

感谢您考虑这一点!

我要试试你的 TypeScriptBuilder ;)

我的建议...

如果编译器没有尝试找到所有部分怎么办? 如果我必须进口其他零件并控制一切怎么办?

/MyClass.partial.ts

export partial class MyClass {
    firstName = "John";
    lastName = "Smith";
}

MyClass.ts

// v- this would NOT throw an error because the definition is marked as partial
import { MyClass } from "./MyClass.partial";

export class MyClass {
    get fullName(): string {
        return this.firstName + ' ' + this.lastName;
    }
}

然后...

  1. 如果我想使用MyClass我必须从MyClass.ts导入它
  2. 编译后, MyClass.partial.ts将生成一个 javascript,它扩展了MyClass.prototype就像之前显示的那样。 但是它导出一个接收要扩展的原型的函数。
  3. MyClass.partial.tsMyClass被定义之后被导入到MyClass并且它的extend函数被调用。

附带说明……没有什么能阻止我直接生成编译后的代码。 但我失去了 Typescript 的所有伟大之处。

@svallory我认为这绝对是正确的方法。 特别是因为您说生成的代码将导出一个会导致扩充的函数,它甚至可以与异步导入一起使用,因为可以以必要的确定性顺序调用这些函数。

更一般地说,我忘记了它被引用的问题,如果对类原型的赋值影响了类的形状,可能会有很多好处。 这将改进 mixin 库,使装饰器更有用,并且通常鼓励较少的垂直层次结构。

编译器跟踪所有这些可能会很棘手,但可能可以按照您的建议通过显式来使其工作。

这将是对类型系统的增强,部分类用例不属于该增强。

我已经这样做了:

我已经这样做了
文件 1  ts
接口ifoo {
 a ( ) :无效;
 }
foo 实现 ifoo {
 a ( ) { /*做某事*/ }
 }
文件 2 . ts
 /// <reference path="file1.ts" /> //没有必要
接口ifoo {
 b ( ) 无效
 } 原型 b = ( ) = > { /*做某事*/ }
文件 3 . ts
 /// <reference path="file1.ts" /> //没有必要
接口ifoo {
 c ( ) :无效;
 }
 (<IFoo> FOO。原型)。 c = ( ) = > { /*做某事*/ }
消费者 ts
 /// <reference path="file1.ts" />
 /// <reference path="file2.ts" />
 /// <reference path="file3.ts" />
让 f =foo ( ) ;
 f .( ) ;
 f .( ) ;
 f . c ( ) ;

模块增强仍然解决了这里 90% 的问题。 鉴于@svallory的例子。

/MyClass.partial.ts

export partial class MyClass {
    firstName = "John";
    lastName = "Smith";
}

MyClass.ts

// v- this would NOT throw an error because the definition is marked as partial
import { MyClass } from "./MyClass.partial";

export class MyClass {
    get fullName(): string {
        return this.firstName + ' ' + this.lastName;
    }
}

模块增强将类似于......

MyClass.ts

export class MyClass {
    firstName = 'John';
    lastName = 'Smith';
}

MyClass.generated.ts

import { MyClass } from './test';

Object.defineProperty(MyClass.prototype, "fullName", {
    get(this:MyClass) {
        return this.firstName + ' ' + this.lastName;
    }
});

declare module './test' {
    interface MyClass {
        readonly fullName: string;
    }
}

它比分部类更冗长,但实际上分部类只是此实现的语法糖。

今天你没有的唯一问题是:

  • 您不能使用this: MyClass语法访问私有或受保护的字段。

    • 这可以通过强制转换为any在生成的代码中轻松解决。

    • 也许这是可以添加的内容,以便您可以访问this受保护成员。 可能还有其他规则。

  • 生成的代码看起来有点吓人,但对于消费者来说,一旦事情被增加,他们永远不会知道其中的区别。

编辑:请记住,这是 TS 2.0+ 语法。

@david-driscoll 我同意。 我认为这更简单,我喜欢它没有引入额外的语法。 如您所知,我反对将部分类作为特定的语言功能,但我确实认为,如果 TypeScript 跟踪对原型的一般分配并相应地改进对象的形状,那将是有益的。 我认为您的方法是在多个文件中拆分类的正确方法。

@wongchichong您的示例使用全局类名和/// <reference path="..."/> 。 我认为这不会很好地扩展,尽管您可以使用命名空间来改善这种情况。
编写为模块(即外部模块)的代码是一个非常不同的野兽,因为它涉及一个加载器,它需要了解依赖顺序和隐式的依赖关系。 这就是为什么@svallory的建议很有价值的原因,它需要非常少量的手动接线,这使得依赖关系变得明确。

如果有人不使用模块怎么办?

@pankleks部分类仍然是一个坏主意。

澄清一下,我的意思是它们在像 JavaScript 这样的语言中是个坏主意,其中类声明是命令式的,而不是声明式的。 即使您使用命名空间,最终也会将代码分解为多个文件,这意味着您必须依赖于这些文件的脚本标记顺序才能使其工作。

在像 C# 这样的语言中,部分类工作得很好,但这是因为它们与 JavaScript 中的类有着根本的不同。

重要的是要记住,在 JavaScript 中,甚至没有提升类声明,更不用说声明性的了。

除 ES6 外,“类”概念由 TS 定义。 JS 根本没有类的概念。
所以它由 TypeScript 来决定一个类可以是什么,不是吗?

除了 ES6,

在讨论 TS 语言特性时,我们不能禁止 ES6,因为 TS 目标之一是遵循当前/未来的 ES 规范

诚然 :/

对于具有代码生成类的大型系统,即实体、服务层客户端等,按照 C# 设计的部分类,当生成的代码需要使用额外的状态和行为进行扩展时,提供了一个非常优雅的解决方案。 在我目前的项目中,我们有大约 500 个代码生成类,我非常想念这个功能。

我仍然不明白为什么有些人对在其他地方已被证明有用的功能如此敌视,除了说“这是一个坏主意”。

似乎这在 esdiscuss 上没有太多讨论,我发现的唯一线程有 9 个帖子。

@yahiko00我并不是对这个概念怀有敌意。 正如您所说,它在 C# 等语言中非常有用。

作为一名热情的 C# 程序员,我发现部分类对某些任务非常有帮助。 但是,它们不会干扰语言的其他方面。 它们不会破坏与关键相关的抽象,例如命名空间、程序集和任意可排序的类型声明。

另一方面,JavaScript 有一个充其量只是新生的模块系统。 类是一个新的,我认为,还不是语言的非常有表现力的特征,它们需要时间来成长。

如果我们退后一步考虑扩展方法,这是 C# 的另一个强大且更有用的特性,我希望看到它们被添加到 JavaScript 中,但这样做有一些基本问题尚未解决。

当我们达到可以在不破坏或严格限制更基本概念(例如模块)的情况下指定部分类的地步时,我将完全赞成添加它们。

也就是说,正如@SaschaNaz指出的那样,这个

也许有兴趣的人可以在http://esdiscuss.org上开个新帖,把网址贴在这里,让我们继续讨论😄

PS:或者在更像 GitHub 的ES Discourse 上
PS2:或者在 GitHub-like-and-more-active WICG 上

我也很想看到一些允许为 TS 生成代码的构造。 分部类在 C# 中非常适用于此。

也许我遗漏了一些东西,但在我看来,核心问题是扩展一个类,该类可以从构造函数以外的其他地方访问“私有”变量,最好是从另一个文件。

根据讨论,似乎已经完成了大部分“安全”TS 创新。 现在我们只是在等待 ES 治理机构做什么,因为我们不想破坏未来的任何事情。 完全有效,但有点令人沮丧,因为我希望能有一辆带 TS 的更快移动的火车。

先决条件是找到一个好的脱糖方法

虽然我以前认为部分类很愚蠢,因为您可以直接添加到类中,但我可以看到它的吸引力,因为这样做将涉及使您的方法不可枚举并修复超级绑定(后者目前在ES6)。

我们首先需要找出一个很好的方法,将一般的类分解为组合的、命令式的原语,比如旧的 toMethod。 但是一旦我们有了它,在顶部添加更多的糖(如部分类)可能是合理的,这取决于人体工程学——或不——这些原语最终是怎样的。

不确定这到底是什么意思,但可能是这样的:

class A {
  foo() { return "foo" }
}
class B extends A {
}

partial(B, class {
  get foo() {
    return super.foo(); // should work
  }
});

(在esdiscuss上交叉发布)

似乎有一种相当简单的方法可以在纯 JS 中实现部分类(使用ES2017 getOwnPropertyDescriptors )。 ES 人可能会认为,甚至不需要语法糖来删除这些微小的代码。

function partial(base, extension) {
  extension.prototype.__proto__ = base.prototype.__proto__; // to enable 'super' reference
  const descriptors = Object.getOwnPropertyDescriptors(extension.prototype);
  delete descriptors.constructor; // must not override constructor
  Object.defineProperties(base.prototype, descriptors);
  
  return base;
}

当然,在 TS 上使用它需要一个interface副本来扩展现有的类类型。

@SaschaNaz我希望通过 getOwnPropertyDescriptors 添加到构造函数的属性将为 IDE“自动建议”隐藏(因为它们是在运行时添加的)。 请记住,Typescript 是作为带有“自动建议”功能的 JavaScript 诞生的(有时人们称其为“强类型”,但实际上他们喜欢的是“自动建议”)。

PS 为什么人们需要部分类 - 代码生成。 但是代码生成应该再次得到 IDE(简单的“工具”调整源文件、文件资源管理器中的分层结果、T4 或类似的“通用代码生成器”支持)和语言(部分类、扩展方法)的支持。 只有在理解了这一点之后,才有可能理解开发人员的真正要求。 如果您没有看到全貌 - 当然“部分课程”看起来像“废话”。

@aluanhaddad :但 TypeScript 的主要功能不是为我们提供 JavaScript 中不存在的语言元素吗? 为什么将一个类分成两个部分 TypeScript 文件,然后将它们编译成一个 JavaScript 文件是个坏主意?

我真的不认为向社区提供工具有什么问题。 而且我 100% 肯定会有开发人员会滥用它。 但也有确切知道如何使用它的开发人员。 但是我们对任何语言的任何构造都没有相同的情况吗?

+1 用于代码生成目的。 而且我同意@rpokrovskij ,为什么我们选择TypeScript,我也可以直接使用JavsScript,因为它看起来像C#,并且有ide 支持。

@greendimka我不知道这如何在不偏离 ES 模块并增加其大量复杂性的情况下工作。

@xiexin36 TypeScript 在我看来更像是 JavaScript 而不是 C#。
JavaScript 和 C# 之间存在共性,但它们的class却截然不同。

@xiexin36用于代码生成,您仍然可以使用模块扩充(正如我在本线程前面提到的)。 从语法上讲,它不像部分类那样“容易”,但您可以完成相同的任务。

@aluanhaddad好吧,它的工作原理非常简单:部分类不会以任何方式更改代码结构。 它们只是允许我们在几个文件中编写同一个类的定义(无论如何它们都被编译成单个 JS)。

@aluanhaddad严格来说:javascript 没有类的概念(ES6 类只是提供了一种语法糖)。 所以,如果我们试图遵循让 TypeScript 像 JavaScript 一样弱的概念——我们不应该从 TypeScript 中扔掉类吗? 我们不应该简单地恢复到 JavaScript 吗?

@greendimka ES6 类和 TypeScript 类是一回事。
TypeScript 并不旨在向 JavaScript 的运行时添加额外的构造。

ES6 类_非常_乏味。 这并不意味着 JavaScript 不是一种强大的语言(它是)。 TypeScript 提供静态类型以在设计时捕获错误,提供高质量的工具,允许对组件接口进行极其精确和严格的规范,并普遍提高生产力。

ES6 类_非常_乏味,但是对于 TypeScript 而言,引入自己的类概念将直接违反其设计目标。

只需避免上课,您的问题就会得到解决。

嗯,它的工作原理很简单:部分类不会以任何方式改变代码的结构。 它们只是允许我们在几个文件中编写同一个类的定义(无论如何它们都被编译成单个 JS)。

并打破几乎所有人类已知的工具? 不,谢谢。

@david-driscoll 谢谢,我会试试的,不过我也用的是 Angular 2.0,不知道能不能用
@Input@Output ,它会起作用,无论如何我会尝试它。

@aluanhaddad看到您如何坚持重复“类?javascript 没有类”是一件痛苦的事情。 从你的脑海中删除类,只留下 JavaScript,然后听听:使用代码生成的开发人员希望在多个文件中拥有一个编译单元。 这种语言没有类,只有函数? 好的,我们想要偏函数。 JavaScript 几乎已经为此做好了准备:可以在声明之前使用那里的函数。 在那里我们当然可以遇到其他问题(例如,确保所有部分/文件都加载到执行环境中),但它们是可以解决的,实际上我们希望在 TypeScript 中有部分编译单元,而不是在 JavaScrpipt 中。 打字稿已为这 100% 做好准备。

顺便说一句,TypeScript 团队也给我们部分功能! 并且请告诉 C# 团队,因为我们现在有“函数中的函数”。 :)

只是为了确保,您确实意识到偏函数具有非常特定的含义,并且您所描述的不是任何想象中的偏函数?
代码生成很有用,我也使用它。

@aluanhaddad 。 您了解“多个文件中的一个编译单元”一词吗? Javascript 当然不是编译语言,但是 a) 函数应该在执行之前完全解析,我们可以将其命名为“编译” b) Typescript 是编译语言。

为了帮助您的想象力:

function partial func(arguments) {
  return function() {
    return codegenerated(arguments);
  };
}

function partial func(arguments) {
   function codegenerated(arguments){
      // ...
   }
}

我也不经常使用部分类:为了有效地使用它们,我们需要将代码生成参数存储在“手动”部分并阅读此配置,我们应该有良好的语言解析器(不是反射)。 但事实就是这样:部分类只是众多工具中的一种,可以让代码生成变得舒适。

@rpokrovskij
如果我表现出敌对态度,我深表歉意。 我没有冒犯或不尊重的意思。

您的示例具有本身需要相当正式的描述的方面。 该提案最初并不是关于直接启用代码生成方案。

@aluanhaddad....
“只要避免上课,你的问题就会得到解决”——说真的,这就是解决问题的方法?! 可能如果我避免使用 JavaScript - 我可以解决整个讨论的问题。 也是一个解决方案,不是吗? 不幸的是,我们的宇宙中有这种糟糕的语言,因为它很幸运多年前进入网络。 无论如何,这是一个题外话。

“破坏几乎所有人类已知的工具”——这怎么可能??? 如何?!?! 我试图想象通过在 TypeScript 中使用部分类来破坏某些东西,但我不能。 我简直不能。 请用一些现实生活中的例子来帮助我。

现在想象你已经造了一辆汽车来运输箱子。 它可以正常工作。 你雇了一个工人,他把车装满了。 工人一次拿两个箱子放进车里。 仍然一切正常。
有一天,工人离开到另一家公司,而你雇用了一家新公司。 新的需要一个盒子,装载它,再拿一个盒子,然后也装载它。 逻辑上:一切正常。 但是你跑来跑去尖叫:停,停,我们有一个系统故障! :)

“只要避免上课,你的问题就会得到解决”——说真的,这就是解决问题的方法?! 可能如果我避免使用 JavaScript - 我可以解决整个讨论的问题。 也是一个解决方案,不是吗? 不幸的是,我们的宇宙中有这种糟糕的语言,因为它很幸运多年前进入网络。 无论如何,这是一个题外话。

ES2015 肯定有很多问题。 ES5.1 肯定有很多问题。 在我看来,缺少课程不是其中之一。 我的观点是,通过使用像揭示模块模式这样的技术,您就不需要部分类了。 TypeScript 为揭示模块模式、命名空间提供了糖。

“破坏几乎所有人类已知的工具”——这怎么可能??? 如何?!?! 我试图想象通过在 TypeScript 中使用部分类来破坏某些东西,但我不能。 我简直不能。 请用一些现实生活中的例子来帮助我。

如果你使用 ES Modules,这是有问题的。 任何依赖于编译器的物理工件与未编译的对应物具有对应关系的工具都将受制于这一点。 也就是说,TypeScript 可以在发出时对此进行调整,这是一个巨大的变化,但它会发出与您编写的 TypeScript 不匹配的 JavaScript。

因此,基本上,语言的进化受到工具的阻碍,如果没有语言的进化,工具就永远不会进化。
对不起,但我在这里看到的只是寻找不进化的原因。

分部类有哪些好处,而您还不能以不同的方式使用该语言? 这是很好的语法糖,当然,但真正的好处是什么? 除了使它更像 C# 之外,还有其他具体的例子吗?


旁白:据记录,我最初是一名 C# 开发人员,从那里转移到 JavaScript/C#。 一旦 TypeScript 0.8 发布,我就被卖掉了,不是因为它是用于 JavaScript 的 C#,而是因为它采用了严格的 JavaScript 并使其更适合喜欢 C# 强类型的开发人员。

TypeScript 不是 C#,并且不应该仅仅因为 C# 拥有它们就严格继承 C# 的特性。 正如 C# 不应该从 TypeScript 继承功能一样。 我数不清我想要 C# 中联合类型等特性的次数,因为它们对于 TypeScript 来说非常棒,但它们还不适合该语言。


到目前为止,我已经阅读了代码生成和代码组织。

代码生成,看看模块增强,我在这里指出了一些缺陷,但我相信它们可以修复。

代码组织,我想使用区域(笑)? 有许多其他方法可以组织您的代码,如果您有一个 God 类(无论出于何种原因),您总是可以将其拆分为多个 God 类。 从表面上看,god 类是每个人都看到和使用的导入,但实际上它是由许多类组成的,也许是作为 God 类的属性。 如果您使用部分类进行组织,我认为您需要稍微重构您的代码以尝试SOLID您的代码。

迄今为止,我已经能够将扩充应用于我遇到的大多数代码生成场景。

对于 Omnisharp-Client,我在这里使用了接口扩展OmniSharp.Api.V2是通过 C# 中的反射生成的。 在文件的底部,我有一个工具,它可以删除该接口的所有方法。

对于 RxJS,我们使用 to 来映射Observable上的所有方法

我只是无法解决部分类的一些问题。 例如,如果我们有 3 个部分类。

  • MyAwesomeClass1.ts
  • MyAwesomeClass2.ts
  • MyAwesomeClass3.ts

范围:全局模块(使用namespace / module

全局编译似乎是最简单的地方。 由于 TypeScript 已经将命名空间合并在一起。

如果我的tsconfig.json仅包含 Class1 和 Class2 的文件路径,则 Class3 中的任何内容都不会自动合并。

  • 起初,这似乎是用户错误,但为什么不包括 Class3 中的方法并不会立即显现出来。 这是一个巨大的可用性问题,会导致混淆。

范围:外部模块(导入/导出)

通过外部编译,每个文件实际上都被视为模块(或 .NET 世界中的地狱程序集),因为每个模块都有一个明确的所有依赖项(导入)列表和所有公共 API(导出)。

你如何推理这些场景?

仅给定一个文件引用,该类的行为是什么?
它会自动合并 Class2 和 Class3 吗?

  • Class1、Class2 和 Class3 的默认定义是否都导出完全相同的值?
  • 什么文件被发送到磁盘?
  • 对于所有支持的格式(amd、umd、commonjs 等),底层 JavaScript 会是什么样子
// somefile.ts
import { MyAwesomeClass } from 'MyAwesomeClass1';

new mac = new MyAwesomeClass();
mac. // What methods are available here?

我们是否必须显式导入类的所有实例? (如果我们这样做就违背了 imo 的目的)。
当您将一个文件中的所有内容(而不是另一个)导入到继承的方法时会发生什么?
这可能会导致非常奇怪的错误,因为在一个复杂的依赖图中,类只使用了一次,而没有额外的部分。 值会增加吗? 或者这些方法会神奇地在加载另一个文件之前不起作用吗?

// somefile.ts
import { MyAwesomeClass } from 'MyAwesomeClass1';
import { MyAwesomeClass } from 'MyAwesomeClass2'; // or maybe import 'MyAwesomeClass2';
import { MyAwesomeClass } from 'MyAwesomeClass3'; // or maybe import 'MyAwesomeClass3';

new mac = new MyAwesomeClass();
mac. // What methods are available here?

@david-driscoll 只有我的两美分:

这是很好的语法糖,当然,但真正的好处是什么?

好的语法糖不是任何语言的全部意义吗? 从操作的角度来看,我们需要的只是循环、if 子句和迭代来完成所有工作。 其余的只是_不错的语法糖_,以提高生产力并提供其他类似的非功能性品质。

虽然语言通常擅长指导计算机的操作部分,但它们通常擅长编写代码的组织部分。 我们有这些文化临时人工制品,如对象、类、继承等,但没有坚实的理论基础,afaik,它真正解释了组织操作的领域以及我们试图在源代码中按顺序构建和表示的所有抽象能够以良好的方式使用它。

我喜欢 TypeScript 的两件事: 1. 它让我们可以使用类型化的 javascript,以便在客户端构建复杂系统突然变得易于管理。 2. 类型系统具有极强的表现力(因为它被迫能够在 javascript 中表达人们可以编写的各种模式,而不受类型系统的限制)。

但是在结构化代码方面,我认为它并不比任何其他语言差很多。 我希望我们可以在这里更具创新性。 给用户更多的自由来试验语言的组织部分。 开放并争取新的结构表现力,而不是限制和怀疑。

分部类不仅特别方便代码生成,而且总体上增加了组织的自由度。 为了摆脱代码组织的这个焦油坑,我们需要自由。

@david-driscoll 有部分有什么意义? 好吧,再一次:代码生成。
您提出的解决方案有什么问题? 这是一种解决方法。 另一个解决方法(和非常肮脏的解决方法)。 我们已经有了一个糟糕的语言(javascrtipt),它充满了变通方法。 javascript 开发人员没有考虑他们的主要任务,而是花大量时间考虑解决方法。 根据您提出的理念,我们可以抛弃整个 TypeScript 语言。 因为(惊喜,惊喜)整个类型系统可以在纯 javascript 中模拟 - 通过使用变通方法。 如果您可以使用变通方法模拟任何内容,为什么还要关心更具表现力的语言(如 Typescript)? 同样的事情可以用二十行来写,为什么还要写一行代码呢? 带回基于编写的多行代码的工资! 简短的、富有表现力的代码是为小猫准备的,不是吗?

不:要求在 TypeScript 中拥有部分不是基于 C# 拥有它们的想法。 我不相信 TypeScript 应该为了拥有它而拥有它,因为另一种语言拥有它。

最后:为什么你认为如果你不使用某些东西 - 没有人需要它?

@greendimka我并不是要激发任何敌意:盾牌:。 我只是想了解这些场景,或者如果有我不知道的场景,坦率地说是完全可能的!

现在请记住,我不是 TypeScript 团队的成员,我只是一个倡导者,但团队在这里一直保持沉默。 当团队有具体的事情要说时,他们很可能会插话,如果他们选择这样做,我会听从他们的意见。

TypeScript 团队坚持的主要租户之一是尝试让 TypeScript 与 ECMAScript 的方向同步,并避免制作任何可能导致它们偏离 JavaScript 发展方向的特定功能。

并不是我不会使用它(如果它存在,我可能会使用)。 问题是在这个问题中,部分类可能有一些警告,所以它是否会很快实现似乎是值得怀疑的。 它可能会保持这种状态一段时间,直到 a) 它成为高价值利益相关者的必备功能或 b) 提案进入 TC39 的后期阶段。

我不认为模块增强是一种解决方法。 它允许您扩充类型系统,并允许在此线程中详细介绍的许多代码生成场景。 这是迈向其他语言功能的一步。

  • 丑吗? 绝对的,丑得像地狱一样。 也就是说,如果您正在生成代码,有什么区别? 只有您的生成工具需要担心如何扩充类。 运行代码生成工具并包含模块后,您会收到完整的智能感知和编译错误等。

  • 它是完美的吗? 离得很远! 我看到了一个更常见的场景,需要在语言级别支持 mixin。 我认为这里提出的与装饰器一致的东西是有道理的,尽管同样没有任何具体的提议。

@david-driscoll,很抱歉非常粗鲁。 我真的倾向于站在积极进步的一边。

我想要这样,所以我可以将静态实现放在部分类中。

由于看起来这不会很快实现,我想提出一个我们找到的解决方法。 有一些这样的评论,但我没有看到有这些细节的评论。

我们希望 Partials 用于代码生成场景,我们希望能够扩展我们生成的 TypeScript 代码。 然而,我们正在生成具有相互依赖性的模型,因此从我们的类继承在传统意义上不能很好地工作。 引用其他类的生成类最终不会引用正确类型的对象,我们最终会使用复杂的工厂模式来创建正确的实例类型。

我们最终将生成的类更改为基类,但仅在类声明中。 然后我们创建了从新基类继承的存根类。 然后我们可以扩展这些新类,它们将从基类继承所有内容。

例如:
如果我们生成一个类 Person,我们现在将生成一个 PersonBase。 所有生成的代码都在这个类中。 我们还将生成一个扩展 PersonBase 的空类 Person。 这个类只会生成一次。 然后我们将所有生成的代码放在 PersonBase 中,所有自定义代码手动进入 Person。 所有生成的对 Person 的引用都保留为 Person 而不是 PersonBase。 这样,所有 IntelliSense 都将继续工作。

文件 1:基类

module ViewModels {
    export class PersonBase {
        // Generated members
        public anotherPerson: Person;
        constructor(){
            // Generated constructor code
        }
    }
}

文件 2:实际班级

module ViewModels {
    export class Person extends PersonBase {
        // Custom methods
        public NewVariable: string = "NewVar";
        constructor() {
            super();
            // Custom constructor code
        }
    }
}

这已经通过生成的代码解决了我们的部分类问题。 感谢 Andrew Scott 提出这个想法。

我也很喜欢这个,因为我正在使用代码生成器生成一些代码,我需要对其进行一些更改。 部分类将允许重新生成代码,而无需稍后再次添加更改(这可能很大或很复杂)

有一个我认为还没有提到的部分类的重要原因:逐渐将 JS 迁移到 TS。 在 Javascript 中,尤其是 ES6 之前,类可能看起来像一堆:

Foo.prototype.someFunction = function() {/*....*/}

这些可以分布在多个文件中而无需任何特殊处理。 将这样的代码库转换为现代 TypeScript 目前需要移动函数,以便类的所有成员都在同一个文件中,这可能是一个非常侵入性的更改。 对于部分类,可以仅使用本地编辑来完成迁移。

@RyanCavanaugh你提到这里要求的所有内容都可以用其他 TypeScript 语法在句法上处理:

我认为 mixin 提案有很多未解决的问题。 这里的部分类提案只是对 TypeScript 中已经允许的东西的编码,只是添加了一些语法糖(这个功能实际上可以作为对我们已经拥有的东西的语法重新映射来完成)。

那么如何在 TypeScript 中做到这一点呢?:
文件1.ts:

// Imagine this file is code generated and could be regenerated during development
export partial class Contact
{
    firstName: string;
    lastName: string;
    partial OnInit( args: any ) : void;
    constuctor( args: any )
    {
        this.OnInit( args );
    }
}
export class Address
{
    addr: string;
    city: string;
    state: string;
    zip: string;
}

文件2.ts

// See where I'm going with this? This file would be hand edited and allows me to specify associations and children.
partial class Contact
{
    Addresses: string[] = [];
    partial OnInit( args: any ) void
    {
        this.firstName = args.firstName;
        this.lastName = args.lastName;
        this.Addresses.push( new Address() );
    }
}

转译上述内容会为 Contact 发出一个 JS 类,如下所示:

var Contact = (function () {
    function Contact() {
         this.Addresses = [];
   }
   Contact.prototype.constuctor = function (args) {
       this.OnInit( args );
   };
   Contact.prototype.OnInit = function (args) {
       this.firstName = args.firstName;
       this.lastName = args.lastName;
       this.Addresses.push(new Address());
   };
   return Contact;
})();

var Address = (function () {
    function Address() {
    }
    return Address;
})();

请注意,最后我想要一个名为 Contact 的类,并且我不想将两个单独的类子类化为第三个类。

@cosmoKenney

这是一个可行的例子。 它不像partial那样在语法上进行了补充,但是它可以工作并且是一个非常实用的解决方案。

// address.ts
export class Address
{
    addr: string;
    city: string;
    state: string;
    zip: string;
}
// contact.impl.ts
import { Address } from './address';

// Class implementation, do the things here that are not code generated
export class Contact {
    firstName: string;
    lastName: string;
    addresses: Address[];
    constructor(args: any) {
        this.onInit(args);
    }
}
// extending the interface here
// define methods you know will need in the constructor only
// This only applies to the constructor however
export interface Contact {
    onInit(args: any): void;
}
// contact.partial.ts
import { Contact } from './contact.impl';

// Implement the extended contract here
Contact.prototype.onInit = function(this: Contact, args: any) {
    this.addresses = args.addresses.concat();
    // do stuff;
};

// Adding another method (not part of the extended interface)
Contact.prototype.somethingAwesome = function(this: Contact) {
    // do awesome stuff here
};

// Tell TypeScript "I added this here!!!!"
declare module './contact.impl' {
    interface Contact {
        somethingAwesome();
    }
}
// contact.ts
import { Contact } from './contact.impl';
import './contact.partial';

// Bring it all together (perhaps there are more than one partial class?)
export { Contact };
// main.ts
import { Contact } from './contact';

// use the contact!
const contact = new Contact(['my', 'args']);
const {firstName, lastName} = contact;
contact.somethingAwesome();

或者,您也可以通过代码生成接口并使用接口扩展实现该接口。

可能还有一些方法可以使用新的 Mixin 功能,但是我自己还没有深入研究,无法给出合格的答案。

@david-driscoll 哇。 我的头简直要爆炸了。

我想知道社区是否会出现一个分叉,它只支持部分类而不会解决问题。
到目前为止,还没有听到任何反对部分类的真正争论。 只有几个理由证明懒惰是正当的。

@greendimka

我想知道社区是否会出现一个分叉,它只支持部分类而不会解决问题。
到目前为止,还没有听到任何反对部分类的真正争论。 只有几个理由证明懒惰是正当的。

不知道你想在这里说什么。 但如果社区内的总体感觉是我们可以使用现有的语言功能实现相同的结果,那么我只需要一些示例来说明如何做到这一点。 @david-driscoll 在上面发布的内容超出了我的理解。 而且似乎并没有完全解决问题。 事实上,据我所知,他误解了我的意图。
我主要关心的是代码生成类的标量属性,如 pojo 或模型类。 但是我需要能够在单独的文件中,甚至在同一个文件中,但不能在主类定义中添加关联属性(以便我可以将新代码生成的主定义粘贴到原始定义上)。
例如,我上面的 Contact 类将使用 firstName 和 lastName 生成代码。 但是,在我的单独定义中,我将添加 Address 对象集合的定义和初始化。
我的代码生成器只知道类的属性,而不知道关联,所以它不能编码生成地址集合——就像在 david 的例子中所做的那样。

@cosmoKenney并不完全清楚地址应该存在于何处。 请原谅我弄错了上下文。 我只是想帮助提供替代方案。 有很多功能可以允许类似的行为,而无需像部分类那样将某些东西放入编译器中,这有很多额外的考虑因素和潜在的问题来实现两个模块系统(内部/外部)。

在您的情况下,生成抽象基类或接口生成会起作用,然后您的其他类继承自该类。 那么你的类被生成的事实仍然是隐藏的。

IE:

// address.partial.ts
export interface IAddress
{
    addr: string;
    city: string;
    state: string;
    zip: string;
}

// address.ts
import { IAddress } from './address.partial';

export class Address
{
    constructor(args: any) {

    }
}
export interface Address extends IAddress{}

// contact.partial.ts
import { IAddress } from './address.partial';

export interface IContact {
    firstName: string;
    lastName: string;
    addresses: IAddress[];
}

// contact.ts
import { Address } from './address';
import { IContact } from './contact.partial';

// Class implementation, do the things here that are not code generated
export class Contact {
    addresses: Address[] = [];

    constructor(args: any) {
        this.firstName = args.firstName;
        this.lastName = args.lastName;
        this.addresses.push( new Address("address?") );
    }

    public somethingAwesome() {
        //
    }
}
export interface Contact extends IContact {}

// main.ts
import { Contact } from './contact';

const contact = new Contact(['my', 'args']);
const {firstName, lastName} = contact;
contact.somethingAwesome();

@cosmoKenney :@david-driscoll 提供了一个有趣的解决方案,但它仍然缺乏真正的部分类的易用性。 正如我的个人实验所表明的那样 - 开发人员根本不使用以这种方式制作的“部分”。 虽然这是一个很好的变通解决方案,但不存在部分的轻松和舒适。

目前我不知道 TypeScript 编译器在内部是如何工作的。 我只能假设它读取所有源文件,处理它们并输出 JS 文件。 如果是这样 - 我认为从多个源文件中读取单个类没有问题。 如果单个类的两个或多个源文件提供了冲突代码(同一属性定义了两次),编译器只会抛出异常。 就像您编写语法无效的代码一样。

@ greendimka ,@david-driscoll
我试图从上面编译大卫的例子,但 ts 不喜欢它:

C:\TestProjects\TypeScriptFakePartialClassTest>tsc -m amd address.partial.ts address.ts contact.partial.ts contact.ts main.ts
address.ts(4,14): error TS2300: Duplicate identifier 'Address'.
address.ts(10,18): error TS2300: Duplicate identifier 'Address'.
contact.ts(7,14): error TS2300: Duplicate identifier 'Contact'.
contact.ts(11,14): error TS2339: Property 'firstName' does not exist on type 'Contact'.
contact.ts(12,14): error TS2339: Property 'lastName' does not exist on type 'Contact'.
contact.ts(20,18): error TS2300: Duplicate identifier 'Contact'.
main.ts(5,8): error TS2459: Type 'Contact' has no property 'firstName' and no string index signature.
main.ts(5,19): error TS2459: Type 'Contact' has no property 'lastName' and no string index signature.

此外,我同意@greendimka 的观点,即这太复杂了,无法在大型应用程序中使用数百次。

@greendimka我也不知道编译器是如何工作的,但不要低估这项任务。 JavaScript 不是 .NET 并且模块不是全局可用的(你应该直接导入它们)

我很想看到这个实现,但是这个任务带来了一些需要仔细考虑的事情,比如:

  • 如果您在文件 A 上定义类的一部分,在文件 B 上定义部分,那么在编译后哪一个应该包含完整的类? 应该生成一个新的?
  • 所有包含部分内容的文件都应该导出相同的类吗?
  • 如果我需要那些附加文件的主文件,如何避免循环依赖?
  • 如果我在模块上导出更多的东西而不仅仅是类本身呢?
  • 名称冲突检查?

等等...

@greendimka请参阅下面的回复:(编辑:这是针对@WoLfulus 的,抱歉 @greendimka):

如果您在文件 A 上定义类的一部分,在文件 B 上定义部分,那么在编译后哪一个应该包含完整的类? 应该生成一个新的?

如果文件 A.js 具有完整定义,而文件 B 被删除,我会非常高兴。 也许有一个罐头评论。 无论如何,我们大多数人都在进行捆绑,因此捆绑的无数 .js 文件最终变成了事后的想法。

所有包含部分内容的文件都应该导出相同的类吗?

我对第一个问题的回答几乎回答了这个问题。

如果我需要那些附加文件的主文件,如何避免循环依赖?

我不知道。 识别这种情况不是模块加载器的工作吗?

如果我在模块上导出更多的东西而不仅仅是类本身呢?

我看不出这有什么问题。 换句话说,如果 B.ts 有部分定义和其他一些非部分类,那么 B.js 应该包含上面提到的罐头注释,以及非部分类的定义。 很简单,我想。

名称冲突检查?

你会如何结束名称冲突? 如果你的意思是在课堂上,那么“部分”关键字将解决这个问题。 但是如果另外两个文件都定义了同名的类,但没有“partial”关键字,编译器应该发出关于重复类型的错误——就像现在一样。 但是,如果您正在谈论定义同名属性或方法的同一类的两个部分定义,则编译器应该发出关于重复成员的错误——就像现在一样。

@WoLfulus@cosmoKenney回答得很好。 只是为了更好地解决您的第一个问题(关于 A 和 B 文件):作为语言设计者,一个人有定义规则的特权。 我的意思是文件 A 可能有这样的代码“部分类 X”,文件 B 可能有这样的代码“部分(fileX)类 X”,这将产生 fileX.js。

@cosmoKenney

如果我需要那些附加文件的主文件,如何避免循环依赖?
我不知道。 识别这种情况不是模块加载器的工作吗?

TypeScript 没有模块加载器。

@greendimka

我想知道社区是否会出现一个分叉,它只支持部分类而不会解决问题。
到目前为止,还没有听到任何反对部分类的真正争论。 只有几个理由证明懒惰是正当的。

这不是一个好主意。 例如,您是否考虑过在添加动态导入时您将如何维护您的 fork?
此外,已经有很多反对部分类的论据。 打破 TypeScript 和 JavaScript 文件之间的源代码对应关系违背了该语言的一个关键原则。 我想一个功能需要启用比部分类更有价值的场景才能被考虑。 它可能仍然会被拒绝。

@WoLfulus@cosmoKenney回答得很好。 只是为了更好地解决您的第一个问题(关于 A 和 B 文件):作为语言设计者,一个人有定义规则的特权。 我的意思是文件 A 可能有这样的代码“部分类 X”,文件 B 可能有这样的代码“部分(fileX)类 X”,这将产生 fileX.js。

我认为你没有传达你的信息。 这听起来好像你觉得用任何语言表达自己时遇到的任何限制都是出于完全任意的原因。
@WoLfulus的问题也没有得到解答,至少没有让我满意。

穿上火焰服

TL;DR:这不会发生。 如果您在第 189 条评论处对此表示反对,请务必先阅读整个主题,因为上面已广泛介绍了不添加此内容的充分理由。

我们对这种情况的解读如下:

  • TypeScript已经有太多 TS 特定的类特性(构造函数属性声明、成员初始值设定项、非终结装饰器、访问修饰符、 implements等),用于真正旨在成为“ES6 + 类型”的东西. 部分原因是我们的错(我们最初的设计方向通常过于 OOP),部分原因是 ES6 的错(五年前类提案移动了很多,我们最终拥有没有实现的功能)。 添加另一个特定于 TS 的类功能是骆驼背上的另一根稻草,我们应该尽可能避免。
  • 毫无疑问,JavaScript 的未来是模块。 部分类仅在“全局汤”模型中才有意义并且运行良好。 允许跨多个模块的部分类是一种灾难,因为加载顺序是不可预测的。 添加仅在全局范围内有效的功能并不是对时间的良好利用。
  • C# 有它,但我们不是来重新发明 C#。 严重地!
  • “生成的代码”场景在优点上并不引人注目。 任何可能的部分类发出都会将属性初始化器和构造函数代码限制为一个声明,这将是.Designer.cs样式设置的破坏者,因为用户代码和生成的代码都可能需要初始化器或构造函数逻辑.
  • JS 中有许多其他可用的组合机制 - mixins、 Object.assign等。导致 C# 中此功能的场景是由 JS 中根本不存在的约束驱动的。
  • interface + prototype.method = ...的当前解决方法确实partial class一样启用了生成代码场景。 手动编写该代码很奇怪,但是以不同的方式生成代码没有问题,所以如果您真的认为拆分文件生成的代码设置是解决您的问题的唯一方法(我持怀疑态度),那么该方法可供您使用.
  • 我们认为 ES6 是类“必备”的仲裁者。 TypeScript 没有什么特别之处(除了它对 C# 程序员的吸引力)使它比非类型化 JavaScript 更需要分部类。 因此,如果有一些场景真的让它无法添加部分类,那么该场景应该能够通过 TC39 流程证明自己是合理的。 如果这获得牵引力,我们很乐意对此进行权衡,但这似乎甚至不在任何人的关注范围内。

@RyanCavanaugh关于这个:

interface +prototype.method = ... 的当前解决方法确实启用了生成代码场景,就像部分类一样。

正如我不止一次提到的那样,我很高兴有一种非部分的、非 c# 的方式来完成我需要的东西,只是要求提供一个工作示例。 david-driscoll 非常有帮助,但发布的代码无法编译。 因此,如果您认为我可以通过代码生成一个仅具有标量属性的类,例如,名字、姓氏——就像上面那样——那很好。 我只需要一种方法来通过手动编码将其他类型的集合添加为类的属性。 但我还需要一种方法来处理该集合的初始化。

@cosmoKenney你是复制了正确代码的网站吗? 第二个例子有接口而不是相同的类名。 如果您愿意,我可以附上代码的 zip。 我只是犹豫,因为互联网上的随机文件可能很糟糕,我不想让你认为我在发布一些恶意的东西 🙂

很抱歉听到这个,但我尊重这里做出的设计决定。 如果可以的话,我有几个问题:

TypeScript 已经有太多 TS 特定的类特性(构造函数属性声明、成员初始值设定项、非终结装饰器、访问修饰符、实现等),用于真正旨在成为“ES6 + 类型”的东西。 部分原因是我们的错(我们最初的设计方向通常过于 OOP),部分原因是 ES6 的错(五年前类提案移动了很多,我们最终拥有没有实现的功能)。 添加另一个特定于 TS 的类功能是骆驼背上的另一根稻草,我们应该尽可能避免。

考虑到这一点,一种可能的前进方式是在组织和代码方面清楚地区分 JS 的纯类型和 TS 提供的其他语言结构吗? 我喜欢打字额外的语言功能。 作为消费者/开发人员,我不太关心 TS 添加了 JS 中没有的东西。 给我一些很棒的东西,如果 TC39 不想要它,我不在乎。

如果 TS 将这些东西相互封装,也许这会更容易重用,并由 SoundScript 之类的项目分叉和构建,而不是被替换?

然后其他项目可以建立在这种类型的基础上,以提供比 JS 提供的更好的/其他语言结构。

毫无疑问,JavaScript 的未来是模块。 部分类仅在“全局汤”模型中才有意义并且运行良好。 允许跨多个模块的部分类是一种灾难,因为加载顺序是不可预测的。 添加仅在全局范围内有效的功能并不是对时间的良好利用。

真的吗? 当然,模块将成为 JavaScript 的自然组成部分,但是主要的原始代码体呢? 我喜欢 namspaces,如果做得好,里面没有汤。 我将它们全部编译成一个文件,并且不需要模块加载器,并且在几乎所有情况下都不需要异步模块加载。 像https://github.com/Microsoft/TypeScript/issues/420这样提出的一些东西只可能与命名空间相关。 你是说这样的事情不会发生,因为我们应该只使用模块? 命名空间是否即将被弃用?

@david-driscoll 谢谢,你已经提供了足够的帮助。 由于@RyanCavanaugh是不断关闭问题并指出有变通方法的人,因此也许他应该提供一个变通方法示例。

我也看到很多关于什么是部分类的误解。 这真的是一个简单的结构,每个人都在夸大其词:
https://msdn.microsoft.com/en-us/library/wa80x488.aspx

考虑到这一点,一种可能的前进方式是在组织和代码方面清楚地区分 JS 的纯类型和 TS 提供的其他语言结构吗? 我喜欢打字和额外的语言功能。 作为消费者/开发人员,我不太关心 TS 添加了 JS 中没有的东西。 给我一些很棒的东西,如果 TC39 不想要它,我不在乎。

那将是一种语言的重写并破坏每个人的代码。

此外,“给我一些很棒的东西”与 TypeScriptCoffeeScriptDartHaxe 。 当然,可能有一些原因为什么它们在采用方面不如 TypeScript 好......

一个不断关闭问题并说明有变通方法的人,也许他应该提供一个解决方法的示例

partial解决的问题有很多用例。 几乎任何语言结构都有许多适用的用例,但出于充分的理由,您必须进行挑选。

您一直要求提供特定的语言功能,例如“我喜欢绿色汽车”,但没有触及问题的关键,为什么汽车需要是绿色的? 如果您解释了为什么您的汽车需要是绿色的,或者您实际上并不关心您的汽车是什么颜色,只要它满足您的实际需求。

我不明白为什么你认为瑞安有义务告诉你如何重新喷漆你的汽车,仅仅因为汽车公司出于正当理由决定不生产绿色汽车。

(哦,TypeScript 2.2 中添加的 mixin 类是完成我怀疑是您真正需要的一个好方法)

interface Base {}

interface Constructor<T> {
    new (...args: any[]): T;
    prototype: T;
}

interface PartialClass {
    foo(): void;
}

function PartialClass<B extends Constructor<Base>>(base: B): B & Constructor<PartialClass> {
    return class extends base {
        foo() {
            console.log('foo');
        }
    };
}

class MyBase {
    bar() {
        console.log('bar');
    }
}

const MyPartialBase = PartialClass(MyBase);

const instance = new MyPartialBase();

instance.bar();
instance.foo();

@kitsonk mixins 不是一回事。

  • Mixin 是可以添加到现有类的独立单元。
  • 分部类可以访问任何其他分部的成员,就好像它们是同一个类的一部分。

作为练习,尝试使用 mixins 实现以下代码拆分:

partial class Point {
  readonly x: number;
  readonly y: number;
}

partial class Point {
  translate(dx: number, dy: number): Point {
    return new Point(this.x + dx, this.y + dy);
  }
}

作为练习,尝试使用 mixins 实现以下代码拆分

回到正题...所以,您不是要指出语言功能,而是要通过示例解决什么问题? 因为 TypeScript 中的解决方法很简单:

class Point {
  readonly x: number;
  readonly y: number;
  translate(dx: number, dy: number): Point {
    return new Point(this.x + dx, this.y + dy);
  }
}

(如果我们是完全主义者,但同样,它解决了一个用途,而不是所有用例)

interface PointBase {
    x: number;
    y: number;
}

interface Constructor<T> {
    new (...args: any[]): T;
    prototype: T;
}

interface TranslatePointPartial {
    translate(dx: number, dy: number): TranslatePointPartial;
}

function TranslatePointPartial<B extends Constructor<PointBase>>(base: B): B & Constructor<TranslatePointPartial> {
    return class TranslatePointPartial extends base {
        translate(dx: number, dy: number): TranslatePointPartial & PointBase {
            return new TranslatePointPartial(this.x + dx, this.y + dy);
        }
    };
}

class Point {
    readonly x: number;
    readonly y: number;
}

const MyPoint = TranslatePointPartial(Point);

const instance = new MyPoint();

instance.x;
instance.y;
instance.translate(1, 2);

@Elephant-Vessel

考虑到这一点,一种可能的前进方式是在组织和代码方面清楚地区分 JS 的纯类型和 TS 提供的其他语言结构吗?

在这一点上,我看不到解开两者的方法。 从理论上讲,可以编写某种语言 ala CoffeeScript,将语法转换为 TypeScript 并使用该高级语言添加新的语法功能,同时仍然使用 TS 的类型系统,但这只能让您到此为止。 如果这是目标,只需选择许多其他未开发的编译为 JS 语言中的一种似乎是更好的选择。

你是说这样的事情不会发生,因为我们应该只使用模块? 命名空间是否即将被弃用?

命名空间不会去任何地方,当然。 它们只是一种已经广泛使用的模式的命名,它们在 ES6 模块的世界中仍然很有意义。 模块越来越多地成为人们组织代码的方式,它们有很多好处。 我只是说部分类在那个世界中几乎没有任何意义,并且添加一个与它不兼容的全新组织模式会很奇怪。 如果世界朝着相反的方向发展,每个人都像“对负载有副作用的全局脚本很棒,每个人都在彼此的prototype s 上聚会”,也许我们会有不同的感受。

@瑞安卡瓦诺

也许是这样......也许它们没有多大意义......但是就像我多次说过的那样,我认为即使在这个线程中,部分类也是为了使代码生成更容易......这是我看到的主要好处来自他们值得 TS 中的功能......我和我必须假设许多其他人,但这只是一个猜测,我目前正在从我的 C# 代码中生成大量 TS 代码......但问题就变成了如何安全地扩展生成的TS代码??? 这是一个更容易用部分类回答的问题......目前我们正在求助于黑客,以便在我们生成的 TS 代码文件中保留自定义代码......

谢谢

同样的事情,我们为我们的 C# API 生成打字稿“代理”,我们希望能够轻松地在打字稿中扩展这些对象。

我不是 JS 专家,所以我一定遗漏了一些东西,因为,我不明白为什么能够在多个 TS 文件中拆分类的声明(编译后只有一个 JS 文件中只有一个类声明)会是JS 世界的一个问题。 在我看来,它对 JS 是透明的,就好像它从一开始就写在一个文件中一样。 我的意思是,无论你是否使用部分类,JS 输出将完全相同,但它会阻止我们开发人员的 JS 对象扩展性成本。

@瑞安卡瓦诺

我想提到的另一件事是,我个人并没有要求 TS 编译器以某种方式解决在使用不同 TS 文件中的部分类创建 ES6 模块时可能出现的打包困境......至少对我来说非常有意义将多个 TS 文件编译为 ES6 模块的单个 js 文件......同样,部分类有助于显着生成代码......它们允许工具创建具有可靠可扩展性的模型的大部分......

@kitsonk

您一直要求提供特定的语言功能,例如“我喜欢绿色汽车”,但没有触及问题的关键,为什么汽车需要是绿色的? 如果您解释了为什么您的汽车需要是绿色的,或者您实际上并不关心您的汽车是什么颜色,只要它满足您的实际需求。

不,我不再要求新功能了。 已经一遍又一遍地说语言可以完成我想要的。 我已经提供了我想要的示例(在 C# 中),但我还没有在有用的示例中看到一种到达我需要的地方的方法。

我不明白为什么你认为瑞安有义务告诉你如何重新喷漆你的汽车,仅仅因为汽车公司出于正当理由决定不生产绿色汽车。

Ryan 似乎是这里的主持人,正在结束这个问题。 这就是为什么。 如果他是语言权威,那么也许他不应该在努力理解我的需求并驳回此请求之前关闭问题,而不提供如何使用母语功能进行操作的示例。 我已经说过我想要一个编译时解决方案。 而且我是一名非常出色的开发人员,并且已经使用许多不同且晦涩的语言进行了一段时间的编程,但我仍然很难使用 mixin 语法。 我不明白这种复杂和难以理解的东西是如何进入语言的,但每个人都拒绝部分类语法的优雅,看起来很简单,因为它是从 C# 借来的。

Ryan 似乎是这里的主持人,正在结束这个问题。 这就是为什么。 如果他是语言权威,那么也许他不应该在努力理解我的需求之前关闭问题

🤔

@RyanCavanaugh ,我知道您已经努力提供帮助。 在这一点上,我继续尝试混合。 或者只是继承,或者也许我太急于完成这个项目,以至于我忽略了使用泛型做到这一点的方法。 唔...
通过继承和命名,我可以做到:

class AddressBase // this is a code generated class
{
    public address: string;
    public city: string;
    public state: string;
    public zip: string;

    constructor( jsonFromService: any )
    {
        this.OnInit( jsonFromService );
    }

    OnInit( jsonFromService: any )
    {
        // could use Object.assign here
        this.address = jsonFromService.address;
        this.city = jsonFromService.city;
        this.state = jsonFromService.state;
        this.zip = jsonFromService.zip;
    }
}

class ContactBase // this is also a code generated class
{
    public firstName: string;
    public lastName: string;

    constructor( jsonFromService: any )
    {
        this.OnInit( jsonFromService );
    }

    OnInit( jsonFromService: any )
    {
        // could use Object.assign here
        this.firstName = jsonFromService.firstName;
        this.lastName = jsonFromService.lastName;
    }
}

// classes that extend the functionality of the code generated classes:
class Address extends AddressBase // subclass simply because I don't want to have to use AddressBase all over my codebase, and then refactor if I ever extend the class
{
}

class Contact extends ContactBase
{
    public Addresses: Address[] = []; // THIS is the customization/extension that cannot be code generated.

    OnInit( jsonFromService: any )
    {
        // note that jsonFromService receives a dto with a array of address info
        super.OnInit( jsonFromService );

        for ( let addr of jsonFromService.Addresses )
        {
            this.Addresses.push( new Address( addr ) );
        }
    }
}

这对我来说很好用。 它没有那么漂亮,并且强制我的代码生成的类具有我不想在代码中使用的名称。 但是,它再次起作用。

目前我觉得那些强烈反对部分类的人只是误解了部分类的概念,他们认为部分类是部分类所没有的东西。

明确地说:部分类是一种语法结构,它允许您将同一个类的定义拆分为多个物理文件。 这里的关键词是“相同”和“单一”。

TypeScript 的文档给出了部分类的错误定义(这里的第一段: https :

真实部分类概念的示例:

文件“Point.generated.ts”:

partial class Point {
   readonly x: number;
   readonly y: number;
}

文件“Point.codeByHand.ts”:

partial class Point {
  constructor(x: number, y: number) {
      this.x = x;
      this.y = y;
  }

  translate(dx: number, dy: number): Point 
  {
      return new Point(this.x + dx, this.y + dy);
  }
}

它们编译成“Point.js”——名称来自类名,而不是文件名:

var Point = (function () {
    function Point(x, y) {
        this.x = x;
        this.y = y;
    }
    Point.prototype.translate = function (dx, dy) {
        return new Point(this.x + dx, this.y + dy);
    };
    return Point;
}());

Mixins,当用作“部分类”(我坚信文档中的这个术语被误用)实际上代表多重继承( https://en.wikipedia.org/wiki/Multiple_inheritance )。

因此,正如我们所见,我们讨论了两种不同的工具:真正的部分类和多重继承。 这是两种不同的工具。 和任何工具一样 - 它们有自己的应用领域。 换句话说:木匠可以用锤子代替木槌,当木槌不可用时,但锤子不是正确的工具。

恕我直言,这个讨论没有未来,我们应该停止它。 虽然我仍然认为真正的部分类没有技术问题,但团队真的不想实现它们,至少现在是这样。

如果可能,TS 团队不希望实现特定于 TS 的功能。 如果您确实想讨论更多,那么这里是一个更好的地方: https :

我希望TC39 端有一个 GitHub 存储库来讨论这些事情,而不是基于邮件的:/

@greendimka

目前我觉得那些强烈反对部分类的人只是误解了部分类的概念,他们认为部分类是部分类所没有的东西。

明确地说:部分类是一种语法结构,它允许您将同一个类的定义拆分为多个物理文件。 这里的关键词是“相同”和“单一”。

我认为这里没有人误解部分类的定义,我认为您可能误解了 JavaScript 中类的定义。

如果您认为 JavaScript 类与几乎任何其他广泛使用的语言中的类完全一样,那么您很可能_看起来_其他人正在误解。

但是,正如在本次讨论中多次说过的那样,我知道我至少明确说过一次,JavaScript 类不是声明性构造,它们是必不可少的。

它们在执行语句之前不存在。

定义它们依赖于变异。

当涉及到继承时,这已经使它们变得脆弱并且依赖于顺序。

这可以一直持续下去......

@cosmoKenney

我不明白这种复杂和难以理解的东西是如何进入语言的,但每个人都拒绝部分类语法的优雅,看起来很简单,因为它是从 C# 借来的。

我真的不认为这是正确的。 每个人都喜欢 C#,即使是 Java 程序员😛,TypeScript 也没有因为与众不同而不同。

@aluanhaddad

我认为您可能误解了 JavaScript 中类的定义......

对于引用及以下内容:我说的是 TypeScript。
正如我所说:我没有看到在 TypeScript 中实现真正的部分类有任何技术问题,这些类将被编译成 JavaScript 的构造。

@greendimka

对于引用及以下内容:我说的是 TypeScript。
正如我所说:我没有看到在 TypeScript 中实现真正的部分类有任何技术问题,这些类将被编译成 JavaScript 的构造。

这个声明的问题是没有 TypeScript 类这样的东西。

好家伙! 有些人会用任何东西作为理由。
好的,TypeScript 中没有类。 或 TypeScript 类。 管他呢。 任何。

我的意思是它们是 JavaScript 类。 虽然我有时会因为迂腐而感到内疚,但我非常明确地做出这种区分,因为我们需要就术语“类”的定义达成一致,然后才能讨论哪些特性可以简单地添加到它们中。

我认为当我们谈论阶级时,我们的意思并不相同,这会导致认知失调并阻碍相互理解。

我认为当我们谈论阶级时,我们的意思并不相同,这会导致认知失调并阻碍相互理解。
完全同意!

事实上,本主题的第一篇文章完美地描述了所要求的内容,因此该讨论没有未来:)

@greendimka是的,它没有未来,因为 TypeScript 似乎永远不会有部分类。 在我看来,这是一件好事。

然而,误会和误会都不是好事,所以我还在和你交谈。

不幸的是,您似乎对两者都不感兴趣

A. 解释 JavaScript 是什么是类,人们可能会改变主意并同意你的观点,即它们可以被简单地部分化。

B. 向他人学习什么是 JavaScript 类,以便您必须理解相反的观点。

我认为这是一种耻辱,但如果你愿意,我不会进一步讨论它。

我不反对任何讨论。 但是这里已经多次声明不会实现部分类(至少现在不会)。 所以我认为最好专注于其他事情。 也许 TypeScript 将来可以改变,谁知道呢。
关于 A 和 B。我讨厌 JavaScript。 但是我非常了解它,当然,我知道类是如何在其中“表示”的。 但是整个讨论的重点不是修改 JavaScript,而是提高 TypeScript 作为高级语言的能力,它生成“低级”JavaScript 代码。
想象一下,我们将用 C++ 替换 TypeScript,用机器代码替换 JavaScript。 机器代码缺少 C++ 中存在的大多数概念。 但是 C++ 应该因此而停止发展吗? 当然不。 它是否应该停止发展,因为一些旧的编译器将无法编译? 当然不 - 您向开发人员提供一个新功能并告诉他们:它适用于新的编译器 - 您(开发人员)决定是否要使用它。

@aluanhaddad
伙计哦伙计。 谁关心等式中的 Javascript 部分? TypeScript 是上面的一层,或者你想用什么来表达它。 还记得旧的 4GL 与 3GL 的讨论吗? TypeScript 之于 Javascript,就像 4GL 之于 3GL 一样。 此外,TypeScript 是具有强类型的 ES6,因此 Partial Classes 不在 TypeScript 路线图的范围内的论点是 LAME。 我们得到了 Mixin、泛型、模块、命名空间和类型转换。 那么为什么不通过部分课程加倍努力呢?

我们想要的只是部分类的语法糖,它使我们能够将单个 TypeScript 类的所有各种定义合并为一个 final - 低级 - 3GL - Javascript 类定义。 对最终的 JavaScript 类定义应该没有影响,对吧? 为什么转译为 Javascript 的最终产品甚至是这次讨论的一部分? 严重地。

@cosmoKenney “它只是带有类型的 ES.next”是转换 JavaScript 开发人员的一大卖点。 如果你想要更多的东西,你正在看错误的语言。 也许试试Scala.js

编辑:我刚刚有一个有趣的认识,即在 ES.next 中,部分类可以使用自定义模块加载器来实现。 如果你使用

import {MyClass} from './myclass.*'

加载器可以将匹配通配符的任何文件中所有导出的 MyClass 定义合并到一个类中,然后提供它。

@spion我喜欢你如何正确地将它们称为 ES.next 部分类。 ES 模块加载器(例如浏览器)或加载器 polyfill(例如 SystemJS)将支持部分类。
在 TypeScript 级别添加此功能的主要问题之一是它破坏了现有工具,例如加载器和打包器。 另一方面,如果 ECMAScript 指定了它们,那么所有这些工具都将实现该功能,并且 TypeScript 将与所有这些工具保持兼容。

我绝对同意你关于 Scala.js 的看法

@cosmoKenney

我们得到了 Mixin、泛型、模块、命名空间和类型转换。 那么为什么不通过部分课程加倍努力呢?

在 TypeScript 中看到的 Mixin 是一种 ECMAScript 设计模式,TypeScript _types_。

泛型是一种类型系统功能,因此它们不适用。

模块是 ECMAScript 的一个特性。

命名空间是 ECMAScript 设计模式的语法糖和形式化。

TypeScript 中不存在类型转换。

@aluanhaddad为什么你一直把它当作运行时的事情? 模块加载器和所有与转译无关的东西。

+1

@cosmoKenney

@aluanhaddad为什么你一直把它当作运行时的事情? 模块加载器和所有与转译无关的东西。

那是不正确的。

看看 SystemJS 和 Webpack 生态系统,你会看到不同的情况。

更传统的、坚如磐石的 gulp 工作流程依赖于输入和输出文件之间的对应关系。

+1

我需要部分类,因为我们使用工具生成大部分基类(在模型发生变化时自动执行)。 然后我们使用部分类在单独的文件中向类添加功能,这样它就不会被工具覆盖(自动生成类)。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

siddjain picture siddjain  ·  3评论

wmaurer picture wmaurer  ·  3评论

Roam-Cooper picture Roam-Cooper  ·  3评论

Zlatkovsky picture Zlatkovsky  ·  3评论

dlaberge picture dlaberge  ·  3评论