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

TypeScript中'{ [key in K]: unknown; } & S["data"]'类型赋值错误修复咨询

TypeScope类型赋值错误修复方案

问题场景

以下代码中setPropertyValueOnScope和getPropertyValueFromScope两个函数存在类型不匹配错误:

export enum Scope {
  Form = "form",
  Nest = "nest",
}

export type ScopeKeyListType<
  L extends Scope,
  T extends ScopeType<L>,
> = T['parent'] extends ScopeType<infer A extends Scope>
  ? keyof T['data'] & ScopeKeyListType<A, T['parent']>
  : keyof T['data']

export type ScopeNestDataType = {
  index: number;
  nest: {
    foo: string;
    bar: boolean;
  };
};

export type ScopeFormDataType = {
  hello: string;
  world: number;
};

export type ScopeTableType = {
  form: ScopeFormDataType;
  nest: ScopeNestDataType;
};

export type ScopeType<
  A extends Scope,
  B extends unknown = unknown
> = {
  data: ScopeTableType[A];
  like: A;
  parent?: B extends ScopeType<infer T extends Scope, infer Q>
    ? B
    : never
};

export type ScopeValueType<
  L extends Scope,
  T extends ScopeType<L>,
  K extends ScopeKeyListType<L, T>,
> = T['data'] extends { [key in K]: unknown }
  ? T['data'][K]
  : T['parent'] extends ScopeType<infer A extends Scope>
  ? ScopeValueType<
      A,
      T['parent'],
      ScopeKeyListType<A, T['parent']>
    >
  : never

export type ParentScopeType<S> =
  | S
  | (S extends ScopeType<infer X, infer Y>
      ? Y extends ScopeType<infer A, infer B>
        ? ParentScopeType<Y>
        : never
      : never)

export function setPropertyValueOnScope<
  L extends Scope,
  S extends ScopeType<L>,
  K extends ScopeKeyListType<L, S>
>(scope: S, property: K, value: ScopeValueType<L, S, K>): void {
  if (property in scope.data) {
    scope.data[property] = value;
  } else if (scope.parent) {
    setPropertyValueOnScope(scope.parent, property, value);
  } else {
    throw new Error(`Property not defined on scope`);
  }
}

export function getPropertyValueFromScope<
  L extends Scope,
  S extends ScopeType<L>,
  K extends ScopeKeyListType<L, S>,
>(scope: S, path: K): ScopeValueType<L, S, K> | undefined {
  let source: ParentScopeType<S> | undefined = scope

  while (source) {
    if (path in source.data) {
      break
    } else {
      source = source.parent
    }
  }

  if (!source) {
    return
  }

  return source.data[path]
}

错误信息

第一个错误(setPropertyValueOnScope函数)

Type 'ScopeValueType<L, S, K>' is not assignable to type 'ScopeTableType[L][K]'.
Type 'S["data"][K] | (S["parent"] extends ScopeType<infer A extends Scope, unknown> ? ScopeValueType<A, S["parent"], ScopeKeyListType<A, S["parent"]>> : never)' is not assignable to type 'ScopeTableType[L][K]'.
Type 'S["data"][K]' is not assignable to type 'ScopeTableType[L][K]'.
Type '{ [key in K]: unknown; } & S["data"]' is not assignable to type 'ScopeTableType[L]'.
Type '{ [key in K]: unknown; } & S["data"]' is not assignable to type 'ScopeFormDataType & ScopeNestDataType'.
Type '{ [key in K]: unknown; } & S["data"]' is not assignable to type 'ScopeFormDataType'.(2322)

第二个错误(getPropertyValueFromScope函数)

Type 'ScopeTableType[L][K]' is not assignable to type 'ScopeValueType<L, S, K> | undefined'.
Type 'ScopeTableType[L][ScopeKeyListType<L, S>]' is not assignable to type 'ScopeValueType<L, S, K> | undefined'.
Type 'ScopeTableType[L][keyof S["data"]] | ScopeTableType[L][keyof S["data"] & ScopeKeyListType<Scope, S["parent"]>]' is not assignable to type 'ScopeValueType<L, S, K> | undefined'.
Type 'ScopeTableType[L][keyof S["data"]]' is not assignable to type 'ScopeValueType<L, S, K> | undefined'.
Type 'ScopeTableType[L][string] | ScopeTableType[L][number] | ScopeTableType[L][symbol]' is not assignable to type 'ScopeValueType<L, S, K> | undefined'.
Type 'ScopeTableType[L][string]' is not assignable to type 'ScopeValueType<L, S, K> | undefined'.(2322)

修复方案

核心问题在于TypeScript无法自动推导嵌套Scope中属性的精确类型关系,需要通过类型断言和优化递归类型定义来解决:

1. 优化ScopeType与ScopeValueType定义

简化泛型逻辑,让类型推导更清晰:

export type ScopeType<
  A extends Scope,
  B extends ScopeType<Scope> | undefined = undefined
> = {
  data: ScopeTableType[A];
  like: A;
  parent?: B;
};

export type ScopeValueType<
  T extends ScopeType<Scope>,
  K extends ScopeKeyListType<Scope, T>,
> = K extends keyof T['data']
  ? T['data'][K]
  : T['parent'] extends ScopeType<infer A extends Scope>
  ? ScopeValueType<T['parent'], K & ScopeKeyListType<A, T['parent']>>
  : never

2. 修复setPropertyValueOnScope函数

通过类型断言明确赋值的类型匹配关系:

export function setPropertyValueOnScope<
  T extends ScopeType<Scope>,
  K extends ScopeKeyListType<Scope, T>
>(scope: T, property: K, value: ScopeValueType<T, K>): void {
  if (property in scope.data) {
    (scope.data as Record<K, ScopeValueType<T, K>>)[property] = value;
  } else if (scope.parent) {
    setPropertyValueOnScope(scope.parent, property, value as ScopeValueType<typeof scope.parent, K>);
  } else {
    throw new Error(`Property not defined on scope`);
  }
}

3. 修复getPropertyValueFromScope函数

添加类型断言确保返回值类型匹配:

export function getPropertyValueFromScope<
  T extends ScopeType<Scope>,
  K extends ScopeKeyListType<Scope, T>,
>(scope: T, path: K): ScopeValueType<T, K> | undefined {
  let source: ParentScopeType<T> | undefined = scope

  while (source) {
    if (path in source.data) {
      break
    } else {
      source = source.parent as ParentScopeType<T> | undefined;
    }
  }

  if (!source) {
    return
  }

  return source.data[path] as ScopeValueType<T, K>;
}

完整修复代码

export enum Scope {
  Form = "form",
  Nest = "nest",
}

export type ScopeKeyListType<
  L extends Scope,
  T extends ScopeType<L>,
> = T['parent'] extends ScopeType<infer A extends Scope>
  ? keyof T['data'] & ScopeKeyListType<A, T['parent']>
  : keyof T['data']

export type ScopeNestDataType = {
  index: number;
  nest: {
    foo: string;
    bar: boolean;
  };
};

export type ScopeFormDataType = {
  hello: string;
  world: number;
};

export type ScopeTableType = {
  form: ScopeFormDataType;
  nest: ScopeNestDataType;
};

export type ScopeType<
  A extends Scope,
  B extends ScopeType<Scope> | undefined = undefined
> = {
  data: ScopeTableType[A];
  like: A;
  parent?: B;
};

export type ScopeValueType<
  T extends ScopeType<Scope>,
  K extends ScopeKeyListType<Scope, T>,
> = K extends keyof T['data']
  ? T['data'][K]
  : T['parent'] extends ScopeType<infer A extends Scope>
  ? ScopeValueType<T['parent'], K & ScopeKeyListType<A, T['parent']>>
  : never

export type ParentScopeType<S> =
  | S
  | (S extends ScopeType<infer X, infer Y>
      ? Y extends ScopeType<infer A, infer B>
        ? ParentScopeType<Y>
        : never
      : never)

export function setPropertyValueOnScope<
  T extends ScopeType<Scope>,
  K extends ScopeKeyListType<Scope, T>
>(scope: T, property: K, value: ScopeValueType<T, K>): void {
  if (property in scope.data) {
    (scope.data as Record<K, ScopeValueType<T, K>>)[property] = value;
  } else if (scope.parent) {
    setPropertyValueOnScope(scope.parent, property, value as ScopeValueType<typeof scope.parent, K>);
  } else {
    throw new Error(`Property not defined on scope`);
  }
}

export function getPropertyValueFromScope<
  T extends ScopeType<Scope>,
  K extends ScopeKeyListType<Scope, T>,
>(scope: T, path: K): ScopeValueType<T, K> | undefined {
  let source: ParentScopeType<T> | undefined = scope

  while (source) {
    if (path in source.data) {
      break
    } else {
      source = source.parent as ParentScopeType<T> | undefined;
    }
  }

  if (!source) {
    return
  }

  return source.data[path] as ScopeValueType<T, K>;
}

修复说明

  • 简化ScopeType的泛型定义,明确parent的类型范围,避免复杂条件判断导致的推导混乱。
  • 调整ScopeValueType的递归逻辑,优先判断属性是否属于当前Scope的data,提升类型推导效率。
  • 通过类型断言告知编译器属性与值的类型匹配关系,解决TypeScript无法自动推导嵌套类型的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:20:39