我想定义从数据库下载的对象类型。
type ActiveOrders = {[orderId: string]: {name: string; price: number}}
const activeOrders: ActiveOrders = {
'orderId1': {name: 'apple', price: 123},
'orderId2': {name: 'banana', price: 123},
'orderId3': {name: 'tesla', price: 99999999},
}
以下代码没问题,并且我的 orderData 保证存在。
for(const orderId in activeOrders) {
const orderData = activeOrders[orderId]
// This is fine, orderData is guaranteed to exist
const {name, price} = orderData
}
这不太好,但是打字稿没有给我任何错误。
someRandomId
可以来自任何地方,例如用户输入的值。
const orderData2 = activeOrders['someRandomId']
// This is NOT fine, orderData2 is possibly undefined, but typescript says it is guaranteed to exist.
const {name, price} = orderData2
我可以将我的类型更改为以下,但我想避免,因为它会弄乱我的 for-in 循环。
type ActiveOrders = {[orderId: string]: {name: string; price: number} | undefined}
有更优雅的解决方案吗?
根据定义,TypeScript 会假设您用来访问此类对象的任何键都是有效的,因为您基本上说过它会是有效的。
您可以使用
noUncheckedIndexedAccess
强制打字稿假设在使用任何任意字符串索引对象时,结果“总是”有可能未定义。
您可以使用条件类型来指定何时假定对象始终已定义以及何时可以未定义(或任何实际情况):
type ActiveOrders = {
[orderId in string|symbol]: orderId extends string ? ({
name: string;
price: number
}|undefined) : {
name: string;
price: number
}
}
const keys : symbol[] = [
Symbol('a'),
Symbol('b'),
Symbol('c')
];
const activeOrders: ActiveOrders = {
[keys[0]]: {
name: 'apple',
price: 123
},
[keys[1]]: {
name: 'banana',
price: 123
},
[keys[2]]: {
name: 'tesla',
price: 99999999
},
}
for(const symbolKey of keys) {
const orderData = activeOrders[symbolKey]
// This is fine, indexed with a symbol the data is assumed to be there
const {name, price} = orderData
}
ActiveOrders
类型如下:
// An ActiveOrders is a map...
type ActiveOrders = {
// with arbitrary string keys in it that correspond to map values...
[orderId: string]: {
// that must contain a `name` key whose value is a string
name: string;
// and a `price` key whose value is a number
price: number;
}
};
根据这个定义,
activeOrders['someRandomId']
是有效的。
ActiveOrders
类型允许任何字符串键存在于其映射中,并且该类型不知道这些键是什么。使用 TypeScript 4.1+,您在定义可接受的密钥的构成方面确实有一些自由,但请记住,虽然您可能使用 TypeScript 进行编码,但您的代码将被转换为 JavaScript,而您的类型不再受支持。 因此,安全检查每个数据确实取决于您;这些类型只是作为开发人员的护栏。如果您想要对数据形状进行某种运行时验证,您可以使用像
yup