typescript - 如何根据 typescript 中的字符串输入更新对象数据?

标签 typescript typescript-generics prisma

我想根据与对象键相关的字符串的输入来更新对象的值,我应该如何使用 typescript 来实现这一点?

const objData = { // random value
  A: 11,
  B: 13,
  C: 53,
  innerObj: {
    AStatus: true,
    BStatus: false,
    CStatus: true,
  },
};

type Item = 'itemA' | 'itemB' | 'itemC';

function processObj(item: Item, obj: typeof objData) {
  if (item === 'itemA') { // <- duplicate
    obj.A = 5;
    obj.innerObj.AStatus = true;
    return obj;
  }

  if (item === 'itemB') { // <- duplicate
    obj.B = 5;
    obj.innerObj.BStatus = true;
    return obj;
  }

  if (item === 'itemC') { // <- duplicate
    obj.C = 5;
    obj.innerObj.CStatus = true;
    return obj;
  }
  return
}

processObj('itemA', objData);

例如,输入是itemA,并且只有A相关的objData被更新。

Typescript playground

最佳答案

如果item之间的关系obj 的参数和键名和obj.innerObj通过字符串操作以编程方式确定,因此有一个属性键 kobj对应属性k+"Status"obj.innerObj并设置为值 "item"+kitem ,那么你可以重构你的 processObj使用函数template literal types 。模板文字类型允许您在类型级别表示一些字符串文字操作。这是一种方法:

type Keys = Exclude<keyof typeof objData, "innerObj">;
// type Keys = "A" | "B" | "C"

function processObj(item: `item${Keys}`, obj: typeof objData) {
  const k = item.substring(4) as Keys; // need to assert here 
  obj[k] = 5;
  obj.innerObj[`${k}Status`] = true;
  return obj;
}

Keys类型用途the Exclude<T, U> utility type过滤 keys of objData删除 "innerObj" ,留给我们 union "A" | "B" | "C" .

对于其余部分,我们使用模板文字类型在类型级别执行字符串连接。 item的类型是 `item${Keys}` ,其计算结果为 "itemA" | "itemB" | "itemC" 。我们可以计算出k来自item通过剥离最初的 "item"来自它的前缀;结果的类型为Keys ,但编译器无法验证这一点。因此我们只是assertk类型为Keys .

我们可以设置obj[k] = 5没有编译器警告,因为编译器知道 obj有一个number Keys 中所有键的属性。我们还可以设置obj.innerObj[`${k}Status`] = true没有编译器警告,因为编译器知道 template literal string value可以有一个模板文字类型,并且类型为 `${k}Status``${Keys}Status` ,其计算结果为 "AStatus" | "BStatus" | "CStatus" 。编译器知道 obj.innerObj有一个boolean这些键上的属性。

所以这一切都按预期进行。


另一方面,如果 item 之间的关系和obj的 key 和obj.innerObj是任意的,那么您不一定可以使用字符串操作来在它们之间进行映射。在这种情况下,您可能需要类似查找表的东西来表示映射,无论它是什么。这样的实现可能如下所示:

const propLookup = {
  itemA: "A",
  itemB: "B",
  itemC: "C"
} as const;
const statusLookup = {
  itemA: "AStatus",
  itemB: "BStatus",
  itemC: "CStatus"
} as const;
type Keys = keyof typeof propLookup;
// type Keys = "A" | "B" | "C"

function processObj(item: Keys, obj: typeof objData) {
  obj[propLookup[item]] = 5;
  obj.innerObj[statusLookup[item]] = true;
  return obj;
}

propLookupstatusLookup对象只是来自有效 item 的映射值 obj 的相应属性和obj.innerObj 。他们正在使用 const assertions所以编译器会跟踪字符串 literal types的值(value)观。如果我们停止as const那么编译器会推断 string对于值(value)观,这对我们没有帮助。

这也可以按需要工作;编译器理解 propLookup[item]obj 的键与 number值,并且 statusLookup[item]obj.innerObj 的键与 boolean值。

Playground link to code

关于typescript - 如何根据 typescript 中的字符串输入更新对象数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71872370/

相关文章:

typescript - Webpack - 提供 core-js polyfills

prisma - Next Auth with Google Provider : To confirm your identity, 使用您最初使用的同一帐户登录

angular - 错误类型错误 : Class constructor EventEmitter_ cannot be invoked without 'new'

typescript - 如何修复 "Type ' BaseCtor' 不可分配给类型 'T'“同时使用带有默认参数的泛型

reactjs - Typescript:没有重复项的元组

typescript - 将命名空间作为通用传递

typescript - 给定判别式,获取判别联合的相应成员的属性类型

typescript - 第二个函数参数的条件类型

javascript - GraphQL:更新数组

typescript - 棱镜 : how can I get all children on a condition?