过滤对象数组时可选 属性 的 TypeGuard
TypeGuards for optional property while filtering array of objects
我在打字稿中有以下接口:
interface ComplexRating {
ratingAttribute1?: number;
ratingAttribute2?: number;
ratingAttribute3?: number;
ratingAttribute4?: number;
}
export interface Review {
rating: ComplexRating | number;
}
为了简单起见,我想计算 ratingAttribute1
的平均评分。
鉴于这些评论:
const reviews: Review[] = [
{ rating: { ratingAttribute1: 5 } },
{ rating: { ratingAttribute1: 10 } },
{ rating: { ratingAttribute2: 15 } },
{ rating: 5 }
]
我可以筛选出我感兴趣的评论,即:
const calculateAverageRating = (reviews: Review[]): number => {
const reviewsWithRating = reviews.filter(
(review) =>
typeof review.rating === 'object' &&
typeof review.rating['ratingAttribute1'] === 'number'
);
return (
reviewsWithRating.reduce((acc, review) => {
let newValue = acc;
if (typeof review.rating === 'object') {
const rating = review.rating['ratingAttribute1'];
if (rating) {
newValue += rating;
}
}
return newValue;
}, 0.0) / reviewsWithRating.length
);
};
现在,令人恼火的是 Typescript 不知道通过 运行 我输入的 reviews.filter
函数只保护评论的子集 rating of type ComplexType
并且那些 ratingAttribute1: number;
而不是 ratingAttribute?: number
.
我希望最终得到的结果是不必在计算中有效地重复类型检查,最终得到:
const calculateAverageRating = (reviews: Review[]): number => {
const reviewsWithRating = reviews.filter(
(review) =>
typeof review.rating === 'object' &&
typeof review.rating['ratingAttribute1'] === 'number'
);
return (
reviewsWithRating.reduce(
(acc, review) => acc + review.rating['ratingAttribute1'],
0.0
) / reviewsWithRating.length
);
};
但这不是开箱即用的:
有什么方法可以实现这种级别的类型保护吗?或者有没有更好的方法来做这类事情?
.filter()
函数总是 return 一个与参数相同类型的数组。这就是 reviewsWithRating
仍然是 Review[]
的原因,即使在您对其进行过滤之后也是如此。
要更改此设置,您可以向回调添加 type guard:
const reviewsWithRating = reviews.filter(
(review): review is { rating: Required<ComplexRating> } =>
typeof review.rating === 'object' &&
typeof review.rating['ratingAttribute1'] === 'number'
);
现在 TypeScript 会知道 reviewsWithRating
的类型是 { rating: Required<ComplexRating> }[]
。
我在打字稿中有以下接口:
interface ComplexRating {
ratingAttribute1?: number;
ratingAttribute2?: number;
ratingAttribute3?: number;
ratingAttribute4?: number;
}
export interface Review {
rating: ComplexRating | number;
}
为了简单起见,我想计算 ratingAttribute1
的平均评分。
鉴于这些评论:
const reviews: Review[] = [
{ rating: { ratingAttribute1: 5 } },
{ rating: { ratingAttribute1: 10 } },
{ rating: { ratingAttribute2: 15 } },
{ rating: 5 }
]
我可以筛选出我感兴趣的评论,即:
const calculateAverageRating = (reviews: Review[]): number => {
const reviewsWithRating = reviews.filter(
(review) =>
typeof review.rating === 'object' &&
typeof review.rating['ratingAttribute1'] === 'number'
);
return (
reviewsWithRating.reduce((acc, review) => {
let newValue = acc;
if (typeof review.rating === 'object') {
const rating = review.rating['ratingAttribute1'];
if (rating) {
newValue += rating;
}
}
return newValue;
}, 0.0) / reviewsWithRating.length
);
};
现在,令人恼火的是 Typescript 不知道通过 运行 我输入的 reviews.filter
函数只保护评论的子集 rating of type ComplexType
并且那些 ratingAttribute1: number;
而不是 ratingAttribute?: number
.
我希望最终得到的结果是不必在计算中有效地重复类型检查,最终得到:
const calculateAverageRating = (reviews: Review[]): number => {
const reviewsWithRating = reviews.filter(
(review) =>
typeof review.rating === 'object' &&
typeof review.rating['ratingAttribute1'] === 'number'
);
return (
reviewsWithRating.reduce(
(acc, review) => acc + review.rating['ratingAttribute1'],
0.0
) / reviewsWithRating.length
);
};
但这不是开箱即用的:
有什么方法可以实现这种级别的类型保护吗?或者有没有更好的方法来做这类事情?
.filter()
函数总是 return 一个与参数相同类型的数组。这就是 reviewsWithRating
仍然是 Review[]
的原因,即使在您对其进行过滤之后也是如此。
要更改此设置,您可以向回调添加 type guard:
const reviewsWithRating = reviews.filter(
(review): review is { rating: Required<ComplexRating> } =>
typeof review.rating === 'object' &&
typeof review.rating['ratingAttribute1'] === 'number'
);
现在 TypeScript 会知道 reviewsWithRating
的类型是 { rating: Required<ComplexRating> }[]
。