You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NgRx Signal Store动态Key调用状态的TypeScript错误解决

修复NGRX Signal Store动态属性的TypeScript类型错误

问题描述

尝试定义可复用的Feature Store,希望状态包含动态定义的属性,代码实现如下:

import {computed} from '@angular/core';
import {signalStoreFeature, type, withComputed} from '@ngrx/signals';

export const withFeature = <Details>(config: { entityName: string }) =>
  signalStoreFeature(
    {state: {[`${config.entityName}Details`]: type<Details>()}},

    withComputed((store) => ({
      [`${config.entityName}ComputedProp`]: computed(() => store[`${config.entityName}Details`]().detailsProp), // TS error here
    })),
  );

出现TypeScript错误:

TS7053: Element implicitly has an any type because expression of type ${string}Details can't be used to index type {}.

需要在保持动态定义属性的前提下修复该错误。

修复方案

严谨型方案(推荐)

核心是通过泛型约束和显式类型定义,让TypeScript能准确推断动态属性的类型:

import {computed} from '@angular/core';
import {signalStoreFeature, type, withComputed, type SignalStoreFeature} from '@ngrx/signals';

// 将entityName约束为字符串字面量类型,让TS跟踪具体属性名
export const withFeature = <Details, EntityName extends string>(config: { entityName: EntityName }) => {
  // 显式定义状态结构,明确动态属性的类型映射
  type FeatureState = {
    [K in `${EntityName}Details`]: Details;
  };

  return signalStoreFeature<FeatureState>(
    {state: {[`${config.entityName}Details`]: type<Details>()} as FeatureState},

    withComputed((store: FeatureState) => ({
      [`${config.entityName}ComputedProp`]: computed(() => 
        store[`${config.entityName}Details` as keyof FeatureState].detailsProp
      ),
    })),
  ) as SignalStoreFeature<FeatureState, {
    [K in `${EntityName}ComputedProp`]: ReturnType<typeof computed<Details['detailsProp']>>;
  }>;
};

关键优化点

  • 新增EntityName泛型并约束为字符串字面量,让TypeScript能识别具体的属性名称
  • 定义FeatureState类型,明确动态属性与Details类型的绑定关系
  • 给store参数指定FeatureState类型,消除索引类型歧义
  • 断言返回的SignalStoreFeature类型,确保计算属性的类型被正确推导

简洁型方案(快速修复)

如果不需要极致严谨的类型推导,可通过类型断言直接告诉TypeScript索引的类型:

import {computed} from '@angular/core';
import {signalStoreFeature, type, withComputed} from '@ngrx/signals';

export const withFeature = <Details>(config: { entityName: string }) =>
  signalStoreFeature(
    {state: {[`${config.entityName}Details`]: type<Details>()}},

    withComputed((store) => ({
      [`${config.entityName}ComputedProp`]: computed(() => 
        (store as Record<string, () => Details>)[`${config.entityName}Details`]().detailsProp
      ),
    })),
  );

内容的提问来源于stack exchange,提问作者Marius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 11:28:27