Skip to content

(eslint-plugin): Enforce type to be called #4797

@rainerhahnekamp

Description

@rainerhahnekamp

Which @ngrx/* package(s) are relevant/related to the feature request?

eslint-plugin

Information

For certain APIs, users need to use the type function to define a type.
Common areas are in signalStoreFeature when defining constraints
for the input or in the Events plugin.

However, it’s easy to forget to call type, which can
lead to subtle and confusing type issues.

INVALID

const loadEvent = event('Load', type<number>); // ⚠️invalid
const bookEvents = eventGroup({
  source: 'Book',
  events: {
    load: type<number>, // ⚠️ invalid
  },
});

In both examples above, if type<number> is not called (i.e., written as
type<number>()), the resulting type of loadEvent or bookEvents.load will
incorrectly be inferred as () => number.

VALID

const loadEvent = event('Load', type<number>()); // ✅ valid
const bookEvents = eventGroup({
  source: 'Book',
  events: {
    load: type<number>(), // ✅ valid
  },
});

We find another common use case in the signalStoreFeature:

INVALID

export function withBaz() {
  return signalStoreFeature(
    {
      props: type<{ foo: Signal<string> }> // ⚠️ invalid
    },
    // ...
  );
}

VALID

export function withBaz() {
  return signalStoreFeature(
    {
      props: type<{ foo: Signal<string> }> () // ✅ valid
    },
    // ...
  );
}

To prevent such mistakes, an ESLint rule should be introduced that verifies
type is always called.

The ESLint rule should also be able to detect an alias of type, like:

INVALID

import { type as defineType } from '@ngrx/signal';

export function withBaz() {
  return signalStoreFeature(
    {
      props: defineType<{ foo: Signal<string> }> // ⚠️ invalid
    },
    // ...
  );
}

VALID

import { type as defineType } from '@ngrx/signal';

export function withBaz() {
  return signalStoreFeature(
    {
      props: defineType<{ foo: Signal<string> }()> // ✅ valid
    },
    // ...
  );
}

Describe any alternatives/workarounds you're currently using

No response

I would be willing to submit a PR to fix this issue

  • Yes
  • No

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions