如何根据打字稿中的字符串输入更新对象数据?
How to update object data based on string input in 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 被更新。
如果 item
参数与 obj
和 obj.innerObj
的键名之间的关系是通过字符串操作以编程方式确定的,这样就有一个 属性 键obj
的k
对应obj.innerObj
的属性k+"Status"
和item
的值"item"+k
,那么就可以重构了您的 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 to filter the keys of objData
to remove "innerObj"
, leaving us with the union"A" | "B" | "C"
.
对于其余部分,我们使用模板文字类型在类型级别执行字符串连接。 item
的类型是 `item${Keys}`
,计算结果为 "itemA" | "itemB" | "itemC"
。我们可以通过从 item
中剥离初始的 "item"
前缀来计算 k
;结果是 Keys
类型,但编译器无法验证这一点。因此我们只是 assert k
是类型 Keys
.
我们可以只设置 obj[k] = 5
而没有编译器警告,因为编译器理解 obj
在 Keys
中的所有键处都有一个 number
属性。我们也可以设置 obj.innerObj[`${k}Status`] = true
而没有编译器警告,因为编译器知道 template literal string value 可以有一个模板文字 type,并且 [= 的类型41=] 是 `${Keys}Status`
,计算结果为 "AStatus" | "BStatus" | "CStatus"
。并且编译器知道 obj.innerObj
在这些键上有一个 boolean
属性。
所以这一切都按预期工作。
另一方面,如果 item
与 obj
和 obj.innerObj
的键之间的关系是任意的,那么您不一定可以使用字符串操作来映射它们.在这种情况下,您可能需要诸如查找 table 之类的东西来表示映射,无论它是什么。这样的实现可能如下所示:
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
assertions so the compiler keeps track of the string literal types 的值。如果我们不使用 as const
,那么编译器只会推断出 string
的值,这对我们没有帮助。
这也符合预期;编译器理解 propLookup[item]
是具有 number
值的 obj
的键,而 statusLookup[item]
是具有 boolean
的 obj.innerObj
的键值。
我想根据与对象键相关的字符串的输入来更新对象的值,我应该如何使用打字稿来处理这个问题?
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 被更新。
如果 item
参数与 obj
和 obj.innerObj
的键名之间的关系是通过字符串操作以编程方式确定的,这样就有一个 属性 键obj
的k
对应obj.innerObj
的属性k+"Status"
和item
的值"item"+k
,那么就可以重构了您的 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 to filter the keys of objData
to remove "innerObj"
, leaving us with the union"A" | "B" | "C"
.
对于其余部分,我们使用模板文字类型在类型级别执行字符串连接。 item
的类型是 `item${Keys}`
,计算结果为 "itemA" | "itemB" | "itemC"
。我们可以通过从 item
中剥离初始的 "item"
前缀来计算 k
;结果是 Keys
类型,但编译器无法验证这一点。因此我们只是 assert k
是类型 Keys
.
我们可以只设置 obj[k] = 5
而没有编译器警告,因为编译器理解 obj
在 Keys
中的所有键处都有一个 number
属性。我们也可以设置 obj.innerObj[`${k}Status`] = true
而没有编译器警告,因为编译器知道 template literal string value 可以有一个模板文字 type,并且 [= 的类型41=] 是 `${Keys}Status`
,计算结果为 "AStatus" | "BStatus" | "CStatus"
。并且编译器知道 obj.innerObj
在这些键上有一个 boolean
属性。
所以这一切都按预期工作。
另一方面,如果 item
与 obj
和 obj.innerObj
的键之间的关系是任意的,那么您不一定可以使用字符串操作来映射它们.在这种情况下,您可能需要诸如查找 table 之类的东西来表示映射,无论它是什么。这样的实现可能如下所示:
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
assertions so the compiler keeps track of the string literal types 的值。如果我们不使用 as const
,那么编译器只会推断出 string
的值,这对我们没有帮助。
这也符合预期;编译器理解 propLookup[item]
是具有 number
值的 obj
的键,而 statusLookup[item]
是具有 boolean
的 obj.innerObj
的键值。