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

将继承父接口的子接口传入泛型接口时丢失类型特异性

动态Shape属性类型推导问题

我尝试创建一个动态接口,能够根据Shape的类型获取其对应属性。示例代码如下:

interface Attributes {
  fill:string|number;
  width:string|number;
  height:string|number;
  stroke:string|number;
  strokeWidth:string|number;
}

interface Circle extends Shape {
  cy:string|number;
  cx:string|number;
  r:string|number;
}

interface Square extends Shape {
  x:string|number;
  y:string|number;
}

interface Polygon extends Shape {
  points:string|number;
}

interface Shape extends Partial<Attributes> {
  [key:string]:string|number|undefined;
}

type ShapeAttributes<T extends Partial<Attributes>, S> = {
  [k in keyof T]:S
}

type ShapeState = {
  currentShapeState:ShapeAttributes<Shape, string|number | undefined>;
} 

const circle:ShapeAttributes<Circle, string|number> = {
  fill:"0",
  stroke:"0",
  strokeWidth:"0",
  width:"0",
  height:"0",
  cx:"0",
  cy:"0",
  r:"0",
}

const square:ShapeAttributes<Square, string|number> = {
  fill:"0",
  stroke:"0",
  strokeWidth:"0",
  width:"0",
  height:"0",
  x:"0",
  y:"0",
}

function shapeState():ShapeState {
  return {
    currentShapeState:circle
  }; 
}

const shape = shapeState();
const innerShape = shape.currentShapeState;

我知道将Shape替换为Circle或Square可以实现需求,但这样属于硬编码,缺乏动态性。在TS Playground中hover查看shape.currentShapeState时,其类型为ShapeAttributes<Shape, string | number | undefined>。我希望能根据传入的具体值(比如circle)自动缩小类型,让innerShape的类型变为ShapeAttributes<Circle,string|number>,请问是否有可行的实现方式?


解决方案

要实现动态推导类型,核心是利用TypeScript的泛型和类型推断能力,让函数根据传入的具体Shape实例自动推导对应类型。具体修改如下:

1. 重构泛型类型定义

将ShapeState改为接受泛型参数的类型,让currentShapeState的类型可以动态关联传入的Shape类型:

type ShapeState<T extends Partial<Attributes>> = {
  currentShapeState: ShapeAttributes<T, string | number>;
};

2. 修改函数为泛型函数

让shapeState函数接收具体的Shape实例作为参数,通过泛型参数自动推断传入的Shape类型:

function shapeState<T extends Partial<Attributes>>(shape: ShapeAttributes<T, string | number>): ShapeState<T> {
  return {
    currentShapeState: shape
  };
}

3. 修复接口循环依赖

原代码中Circle等接口继承Shape,但Shape定义在这些接口之后,会导致循环依赖。调整定义顺序:

interface Shape extends Partial<Attributes> {
  [key: string]: string | number | undefined;
}

interface Circle extends Shape {
  cy: string | number;
  cx: string | number;
  r: string | number;
}

interface Square extends Shape {
  x: string | number;
  y: string | number;
}

interface Polygon extends Shape {
  points: string | number;
}

完整修改后代码

interface Attributes {
  fill:string|number;
  width:string|number;
  height:string|number;
  stroke:string|number;
  strokeWidth:string|number;
}

interface Shape extends Partial<Attributes> {
  [key:string]:string|number|undefined;
}

interface Circle extends Shape {
  cy:string|number;
  cx:string|number;
  r:string|number;
}

interface Square extends Shape {
  x:string|number;
  y:string|number;
}

interface Polygon extends Shape {
  points:string|number;
}

type ShapeAttributes<T extends Partial<Attributes>, S> = {
  [k in keyof T]:S
}

type ShapeState<T extends Partial<Attributes>> = {
  currentShapeState:ShapeAttributes<T, string|number>;
} 

const circle:ShapeAttributes<Circle, string|number> = {
  fill:"0",
  stroke:"0",
  strokeWidth:"0",
  width:"0",
  height:"0",
  cx:"0",
  cy:"0",
  r:"0",
}

const square:ShapeAttributes<Square, string|number> = {
  fill:"0",
  stroke:"0",
  strokeWidth:"0",
  width:"0",
  height:"0",
  x:"0",
  y:"0",
}

function shapeState<T extends Partial<Attributes>>(shape: ShapeAttributes<T, string | number>): ShapeState<T> {
  return {
    currentShapeState: shape
  }; 
}

const shape = shapeState(circle);
const innerShape = shape.currentShapeState; // 类型自动推导为ShapeAttributes<Circle, string | number>

const squareShape = shapeState(square);
const innerSquare = squareShape.currentShapeState; // 类型自动推导为ShapeAttributes<Square, string | number>

关键说明

  • 泛型函数shapeState通过接收具体的Shape实例,让TypeScript自动推断泛型参数T的类型,从而动态生成对应的ShapeState类型。
  • 调整接口定义顺序解决了循环依赖问题,确保类型解析正确。
  • 现在无论传入circle还是square,currentShapeState的类型都会自动缩小为对应的具体Shape属性类型,无需硬编码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 17:53:16