如何根据字符串输入在 TypeScript 中更新对象数据?
我想根据与对象键相关的字符串输入更新对象的值,我应该如何使用 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 游乐场
答案#1
如果 item 参数与 obj 和 obj.innerObj 的键名之间的关系是通过字符串操作以编程方式确定的,那么存在一个 obj 的属性键 k 对应 obj.innerObj 的一个属性 k+"Status",并对应 item 的值 "item"+k,那么你可以重新构造你的 processObj 函数以使用模板字面量类型。模板字面量类型允许你在类型层面表示一些字符串字面量操作。以下是实现的一种方式:
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 类型使用 Exclude<T, U> 工具类型来筛选 objData 的键,以移除 "innerObj",从而得到联合类型 "A" | "B" | "C"。
对于其余部分,我们使用模板字面量类型在类型级别执行字符串连接。item 的类型是 `item${Keys}`,它会计算为 "itemA" | "itemB" | "itemC"。我们可以通过从 item 中去掉初始的 "item" 前缀来计算 k;结果类型为 Keys,但编译器无法验证这一点。因此,我们只是断言 k 的类型是 Keys。
我们可以直接设置 obj[k]=5 而不会有编译器警告,因为编译器理解 obj 在 Keys 的所有键上都有 number 类型的属性。我们也可以设置 obj.innerObj[`${k}Status`]=true 而不会有编译器警告,因为编译器理解模板字面量字符串值可以有模板字面量类型,并且 `${k}Status` 的类型是 `${Keys}Status`,它的值会被计算为 "AStatus" | "BStatus" | "CStatus"。编译器也知道 obj.innerObj 在这些键上有 boolean 类型的属性。
所以这一切都按预期工作。
另一方面,如果 item 与 obj 和 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;
}
propLookup 和 statusLookup 对象只是从有效的 item 值映射到 obj 和 obj.innerObj 对应属性的映射。它们使用了 const 断言,因此编译器会跟踪这些值的字符串字面量类型。如果我们省略 as const,编译器就只会推断出 string 类型的值,这对我们没有帮助。
这也按预期工作;编译器理解 propLookup[item] 是 obj 的一个键,其值为 number,并且 statusLookup[item] 是 obj.innerObj 的一个键,其值为 boolean。
代码的 Playground 链接
