microsoft / microsoft/TypeScript

Suggestion: Reopen static and instance side of classes

Đang mở
#2,957 16 bình luận 30 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

In Discussion Suggestion
Ngôn ngữ chính
Go
Star
111k
Fork
14.3k
Merge trung bình
2 ngày 4 giờ
Pull request đã merge (30 ngày)
132

Mô tả

Summary

To support both the semantics of subclassing built-ins in ES6 and still allow authors to augment built-ins, we need a mechanism to reopen the static and instance sides of a class.

Current state

Today we can re-open interfaces, allowing authors to augment built-ins (for example, to support polyfills):

// in lib.d.ts
interface Array<T> { /*...*/ }
interface ArrayConstructor { /*...*/ }
declare var Array: ArrayConstructor;

// in polyfill.ts
interface Array<T> {
  includes(value: T): Boolean;
}
interface ArrayConstructor {
  of<T>(...items: T[]): Array<T>;
}

Array.prototype.includes = function (value: any) { return this.indexOf(value) != -1; }
Array.of = function<T> (...items: T[]) { return items; }

We can also re-open the static side of a class, in a limited fashion:

// initial declaration
class MyClass {
}

// re-open
module MyClass {
  export var staticProperty = 1;
}

There are several issues with these approaches:

  • You cannot use type defined by the var/interface pattern in the extends clause of a class in TypeScript, meaning that "classes" defined using this pattern cannot be subclassed in ES6, which is an issue for built-ins.
  • While you can re-open the static side of a class using module, you can only use non-keyword identifiers for property names. So you could not, for example, add a [Symbol.species] property to the class, or use decorators on these members.
  • There is no way to re-open the instance side of a class.

Proposal

I propose we add a new syntactic modifier for the class declaration that would indicate we are re-opening an existing class. For this example I am using the keyword partial, although the semantics here differ significantly than the same-named capability in C#:

// in lib.d.ts
declare class Array<T> {
}

// in polyfill.ts
partial class Array<T> {
  static of<T>(...items: T[]) { return items; }
  includes(value: T): boolean { return this.indexOf(value) != -1; }
}

// emit (ES5)
Array.of = function() { 
  var items = [];
  for (var _i = 0; i < arguments.length; i++) 
    items[i] = arguments[i];
  return items;
}
Array.prototype.includes = function(value) {
  return this.indexOf(value) != -1;
}

Rules

  • A partial class declaration must be preceded by a non-partial class declaration in the same lexical scope. These should be the same rules that apply when merging a module with a class or function today.
  • A partial class declaration must have the same module visibility as the preceding non-partial class declaration.
  • A partial class declaration must have the same generic type parameters (including constraints) as the non-partial class declaration.
  • A partial class declaration cannot have an extends clause, but may have an implements clause.
  • A partial class declaration cannot have a constructor member.
  • A partial class declaration cannot have members with the same name as existing members on a class.
    • Exception: ambient partial class declaration members can merge with other ambient partial class declaration members if they are compatible overloads, similar to interfaces.
  • Non-static property declarations on a partial class declaration cannot have initializers.
  • A partial class declaration can have a class decorator. User code that executes in-between the initial class declaration and the partial declaration will be able to observe the class before decorators on the partial class are applied.
    • NOTE: We could choose to disallow class decorators on a partial class.

Out of scope

  • This proposal does not cover the case where built-in "classes" can often also be called as functions. This case is covered in #2959.
  • This proposal does not cover the case where authors may have already extended the interface of a built in. This case is covered in #2961.

Previous discussions

This has also been discussed previously:

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu bằng cách đọc các ví dụ trong proposal và các cuộc thảo luận trước đó được tham chiếu trong #9, #563 và work item CodePlex được liên kết. Payload không nêu tên các tệp repository, test hoặc entry point; để hoàn thành, cần triển khai và xác thực các quy tắc partial-class được đề xuất, việc hợp nhất static và instance, decorators, và đầu ra ES5.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
javascript, typescript
Lĩnh vực
compilers
Loại issue
Tính năng
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
25/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.