Skip to content

[Feature]: Update ServiceIdentifier without Function#1071

Description

@notaphplover

馃殌 Feature Proposal

ServiceIdentifier is currently defined as follows:

type AbstractNewable<
  TInstance = unknown,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  TArgs extends unknown[] = any[],
> = abstract new (...args: TArgs) => TInstance;

type Newable<
  TInstance = unknown,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  TArgs extends unknown[] = any[],
> = new (...args: TArgs) => TInstance;

export type ServiceIdentifier<TInstance = unknown> =
  | string
  | symbol
  | Newable<TInstance>
  | AbstractNewable<TInstance>
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
  | Function;

The proposal consist in removing Function from ServiceIdentifier type union:

type AbstractNewable<
  TInstance = unknown,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  TArgs extends unknown[] = any[],
> = abstract new (...args: TArgs) => TInstance;

type Newable<
  TInstance = unknown,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  TArgs extends unknown[] = any[],
> = new (...args: TArgs) => TInstance;

export type ServiceIdentifier<TInstance = unknown> =
  | string
  | symbol
  | Newable<TInstance>
  | AbstractNewable<TInstance>;

Motivation

Function is causing trouble as reported at #1036. Removing Function would help the type system to provide an enhanced developer experience and safer types.

The drawback of this would be the following one: classes with protected or private constructors will no longer be valid service identifiers.

Classes are used as service identifiers to easily bind a class to a container. At first glance, it doesn't make a lot of sense to bind a class with protected / private constructors. If you don't want your constructor to be called, it makes sense not to be bound to the container, avoiding calling the constructor by the container's resolver.

After reading this comment, I realiced some developers might be using this pattern. While I understand this approach, I honeslty believe using a symbol as service identifier instead of the abstract class is a better alternative. Class service identifiers are supposed to be a straightforward way to bind classes.

Example

No response

Pitch

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

Relationships

None yet

Development

No branches or pull requests

Issue actions