microsoft / microsoft/TypeScript

generics in constructor

Đang mở
#62,992 4 bình luận 1 reaction 0 người được giao Xem trên GitHub

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

Awaiting More Feedback 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ả

🔍 Search Terms
  • "generics in constructor"
  • "generics"
  • "constructor"
  • "private class generics"
  • "private generics"
✅ Viability Checklist
⭐ Suggestion

I'd like to know if we can add the capability to have generics in constructors ; after all they are functions like any other, and some parameters of constructor could require generics to extend a type for any reason.

type Foo = {
  foo: string
}

class Bar {
  constructor<T extends Foo>(foo: T) {
    // do something with foo: T shape
  }
}
📃 Motivating Example

My real-life use-case is to implement a base repository class, which would need a property typed when calling super() for which i need to keep type integrity, therefore i'd need to be able to use extends in constructor:

// ↓ types to understand why need type integrity (→ iterate on keys)
type SimpleProjection<T> = {
  [K in keyof T]?: boolean
}

type FilterKeysWhenEquals<T extends object, V> = keyof {
  [K in keyof T as T[K] extends V ? K : never]: T[K]
}

type FilterKeysWhenDiffers<T extends object, V> = keyof {
  [K in keyof T as T[K] extends V ? never : K]: T[K]
}

type HasFalse<T extends object> = T[keyof T] extends false ? true : false

type Projected<
  Schema extends object,
  Projection extends object | undefined,
  DefaultProjection extends object | undefined,
> = Projection extends undefined
  ? Schema
  : HasFalse<Projection & {}> extends true
    ? // Exclusion mode
      Omit<Schema, FilterKeysWhenEquals<(Projection & {}) | (DefaultProjection & {}), false>>
    : // Inclusion mode
      Pick<Schema, FilterKeysWhenDiffers<Projection & {}, false>>

// ↓ said class
export class Repository<
  Schema extends object,
  DefaultProjection extends ExclusionProjection<Schema> | undefined = undefined,
> {
  constructor(
    protected model: Model<Schema>,
    protected projection?: DefaultProjection,
  ) {}

  async findById<Projection extends SimpleProjection<Schema> | undefined = undefined>(
    id: ID,
    projection?: Projection,
  ) {
    return this.model
      .findById(id, this.mergeProjection(projection))
      .lean<Projected<Schema, Projection, DefaultProjection>>({ transform })
  }
}

// ↓ current usage
const EXCLUDE_DEFAULTS = { passkeys: false, password: false, salt: false } as const

export class UserRepository extends Repository<User, typeof EXCLUDE_DEFAULTS> {
  constructor() {
    super(new UserModel(), EXCLUDE_DEFAULTS)
  }
}

but if i could have generics in constructor, i would be able to write:

// ↓ one generic at class level, the 2nd one in constructor
export class Repository<Schema extends object> {
  constructor<
    DefaultProjection extends ExclusionProjection<Schema> | undefined = undefined,
  >(
    protected model: Model<Schema>,
    protected projection?: DefaultProjection,
  ) {}

  async findById<Projection extends SimpleProjection<Schema> | undefined = undefined>(
    id: ID,
    projection?: Projection,
  ) {
    return this.model
      .findById(id, this.mergeProjection(projection))
      .lean<Projected<Schema, Projection, typeof this.projection>>({ transform })
  }
}

// ↓ can inline the object directly, no need to create a const just so that i can pass `typeof theConst` in 2nd generics
export class UserRepository extends Repository<User> {
  constructor() {
    super(new UserModel(), { passkeys: false, password: false, salt: false })
  }
}
💻 Use Cases
  1. What do you want to use this for? Have simpler syntax when writing constructors

  2. What shortcomings exist with current approaches? Need to complicate class generics and merge them with constructor generics (which could be 2 different scopes sometimes)

  3. What workarounds are you using in the meantime? manual mode. verbose and need specific structure, but acceptable enough at least for my use-case.

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

Không có tệp triển khai hoặc bài kiểm thử nào được nêu tên. Hãy bắt đầu bằng cách xem xét cú pháp tham số kiểu được đề xuất cho constructor và các ví dụ generic hiện có về class và method trong issue, sau đó theo dõi cách TypeScript xử lý chữ ký constructor và suy luận kiểu. Để được xem là hoàn tất, cần có một thiết kế đã được thống nhất và hành vi tương ứng của compiler, đồng thời vẫn bảo toàn các ràng buộc đã nêu đối với đầu ra JavaScript.

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

Đánh giá

Công nghệ
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
35/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.