如果我要创建一个简单的对象,如下面的类型,我想创建一个函数,该函数接受对象、对象的有效键和基于对象键的值的类型的有效值.

export interface MyType {
    prop1: string;
    prop2?: number;
    prop3?: string[];
  }

我发现我可以很容易地使用keyOf MyType方法输入更新函数,从而只允许类型的有效属性.

propertyName: keyOf MyType;

我还发现,我可以通过访问键上的类型来输入值.下面的代码应该是一个字符串.

propertyValue: MyType["prop1"];

然而,我在使用所有可能的键--pro1、pro2和pro3--键入PropertyValue时遇到了麻烦.

export interface MyType {
    prop1: string;
    prop2?: number;
    prop3?: string[];
  }
  const instanceOfMyType: MyType = {
    prop1: "hello"
  }`

  const updatePropOfMyType = (thingBeingUpdated: MyType, 
    propertyName: keyof MyType,
    propertyValue: MyType[typeof propertyName]): MyType
    =>{
      const updatedType = _.cloneDeep(thingBeingUpdated);

      updatedType[propertyName] = propertyValue; 

      return updatedType; 
    };

Expected output:

const updatedInstanceOfMyType = updatePropOfMyType(instanceOfMyType, "prop2", 123);

console.log(updatedInstanceOfMyType)
// Expecting output {prop1: 'hello", prop2: 123}`

类似

const anotherUpdatedInstanceOfMyType = updatePropOfMyType(instanceOfMyType, "prop2", "hi");
//should give me a type error since prop2 is a number not a string;

Actual output

相反,我有一个类型错误 "类型‘STRING|NUMBER|STRING[]|UNDEFINED’不可分配给类型‘Never’. 类型‘unfined’不可赋值给类型‘Never’."at the updatdType[PropertyName]=PropertyValue;

这似乎是因为TypeScrip将MyType属性的所有可能类型连接在一起,而不是为当前设置的PropertyName值过滤类型.

我只是想看看是否有一种方法可以动态地强制PropertyValue的类型与基于当前设置的PropertyName;的值的给定属性相同;

推荐答案

如果希望编译器跟踪为propertyName传入的特定参数与propertyValue类型之间的关系,则应将propertyName constrainedkeyof MyType的类型K设置为updatePropOfMyType generic,如下所示:

const updatePropOfMyType = <K extends keyof MyType>(thingBeingUpdated: MyType,
    propertyName: K,
    propertyValue: MyType[K]): MyType => {
    const updatedType: MyType = structuredClone(thingBeingUpdated)
    updatedType[propertyName] = propertyValue;
    return updatedType;
};

这将为您提供您想要的呼叫行为:

const updatedInstanceOfMyType =
    updatePropOfMyType(instanceOfMyType, "prop2", 123); // okay
console.log(updatedInstanceOfMyType);
const anotherUpdatedInstanceOfMyType =
    updatePropOfMyType(instanceOfMyType, "prop2", "hi"); // error
// 'string' is not assignable to 'number' ------> ~~~~

您的原始版本不起作用,因为propertyName的类型是完整的union type keyof MyType,并且编译器无法识别"当前设置的"类型,因此typeof propertyName也是完整的并集.通过使propertyName的类型成为泛型,您允许编译器将propertyNamekeyof MyType缩小到某个特定的literal type,然后再使用它来缩小propertyValue.

Playground link to code

Typescript相关问答推荐

通用默认值触发依赖通用约束变量的错误

排序更改数组类型

如何根据参数的值缩小函数内的签名范围?

在React中实现具有独立页面的嵌套路径的最佳实践是什么?

TypeScript将键传递给新对象错误

TypeScript实用程序类型—至少需要一个属性的接口,某些指定属性除外

如何在排版中正确键入中间件链和控制器链

对深度对象键/路径进行适当的智能感知和类型判断,作为函数参数,而不会触发递归类型限制器

打字脚本中泛型和直接类型重新映射的不同行为

使用打字Angular 中的通用数据创建状态管理

通过按键数组拾取对象的关键点

错误TS2403:后续变量声明必须具有相同的类型.变量';CRYPTO';的类型必须是';CRYPATO';,但这里的类型是';CRYPATO';

如何在深度嵌套的Reaction路由对象中隐藏父级?

如何在ANGLE中注册自定义验证器

尽管对象的类型已声明,但未解析的变量<;变量

防止重复使用 Select 器重新渲染

在VSCode中显示eslint错误,但在终端中运行eslint命令时不显示?(Vite,React,TypeScript)

在Cypress中,您能找到表格中具有特定文本的第一行吗?

为什么特定的字符串不符合包括该字符串的枚举?

是否可以将类型参数约束为不具有属性?