首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Typescript泛型约束为变量属性时不起作用

Typescript泛型约束为变量属性时不起作用
EN

Stack Overflow用户
提问于 2021-10-13 10:46:45
回答 1查看 44关注 0票数 0

当typescript被用来动态访问对象的属性(在方括号内)时,我正在尝试让typescript generic工作。

**最小示例:**

代码语言:javascript
运行
复制
export type TaskType = 'withdraw' | 'pickup'

interface Task<T extends TaskType = TaskType> {
  val: number
}

interface Memory {
  tasks : {
    [T in TaskType] : {
      [targetId: string]: Task<T>
    }
  }
}

const data: Memory = {
  tasks : {
    withdraw : {
      'a' : {val:  0}
    },
    pickup : {
      'a' : {val: 0}
    }
  }
}

const res1 =  data.tasks.withdraw.a; // Type is set correctly to Task<"withdraw">


let fn = function<T extends TaskType>(taskType: T) {
  const res2 = data.tasks[taskType].a; 
  // ^ Type here is not being infered. It is Task<"withdraw"> | Task<"pickup">
};

Link to TS Playground

正如您在上面的示例中看到的,当使用特定的键在函数外部调用时,res1将返回正确的类型。

但当使用变量data.tasks[taskType].a;时,它就不起作用了。res2的类型应该是Task<T>,而不是其他类型。我做错了什么?

更新:更多信息

我觉得我应该对我的实际问题进行更多的阐述。不同TaskTypes之间的实际Task接口不会重叠。我还有一个如下所示的函数。

代码语言:javascript
运行
复制
interface Task<T extends TaskType = TaskType> {
  val: number
  resourceType: T extends 'withdraw' ? string : undefined
}
...
let claim = <T extends TaskType>(taskType: T, task: Task<T>) => {
  data.tasks[taskType].a = task;  // Why is task not assignable here ?
}

Link to TS Playground

因为不同字符串之间的Task<T>没有相同的属性,所以data.tasks[taskType].a = task;行抛出一个错误。

我像这样调用索赔函数:

代码语言:javascript
运行
复制
const pickupTask = {val: 0, resourceType: undefined} as Task<`pickup`>;
claim('pickup', pickupTask) // The function will always be called with the same tasktype i.e. calling claim('withdraw', pickupTask) should throw an error

从逻辑上讲,既然是taskType='pickup',那么参数pickupTask应该能够被赋值给data.tasks[taskType].a。那么为什么会抛出一个错误呢?我可能误解了typescript泛型,但我不确定我错在哪里。

另外,我不能将内存接口更改为通用接口。

EN

回答 1

Stack Overflow用户

发布于 2021-10-13 11:43:31

您需要对类型进行小的重构,并将data作为参数之一。

代码语言:javascript
运行
复制
export type TaskType = 'withdraw' | 'pickup'

interface Task<T extends TaskType = TaskType> {
  val: number
}

type Memory<Type extends TaskType> = {
  tasks: {
    [T in Type]: {
      [targetId: string]: Task<T>
    }
  }
}

const data: Memory<TaskType> = {
  tasks: {
    withdraw: {
      'a': { val: 0 }
    },
    pickup: {
      'a': { val: 0 }
    }
  }
}

const res1 = data.tasks.withdraw.a; // Type is set correctly to Task<"withdraw">


const fn = <
  Key extends TaskType,
  Data extends Memory<Key>
>(data: Data, taskType: Key) => {
  const res2 = data.tasks[taskType].a; // Task<Key>
};

Memory -应该使用feneric Type

Playground

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69554116

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档