Browse Source

ref(ts): Prefer reduce template over `as`ing (#50547)

See https://typescript-eslint.io/rules/prefer-reduce-type-parameter

> A better solution is to pass the type in as a generic type argument to
> Array#reduce explicitly. This means that TypeScript doesn't have to
try
> to infer the type, and avoids the common pitfalls that come with
> casting.
Evan Purkhiser 1 year ago
parent
commit
6e11999d82

+ 2 - 2
static/app/__mocks__/react-date-range.tsx

@@ -88,13 +88,13 @@ export function DateRange({ranges, onChange}: DateRangeProps) {
         <DateRangeInputs
           range={range}
           onChange={({startDate, endDate, key}) => {
-            const rangesByKey = ranges?.reduce(
+            const rangesByKey = ranges?.reduce<RangeKeyDict>(
               (acc, nextRange) => ({
                 ...acc,
                 [nextRange?.key ?? '']:
                   nextRange.key === key ? {...nextRange, startDate, endDate} : nextRange,
               }),
-              {} as RangeKeyDict
+              {}
             );
 
             onChange?.(rangesByKey);

+ 5 - 5
static/app/components/events/interfaces/spans/utils.tsx

@@ -861,7 +861,10 @@ export function getFormattedTimeRangeWithLeadingAndTrailingZero(
     };
   }
 
-  const newTimestamps = startStrings.reduce(
+  const newTimestamps = startStrings.reduce<{
+    end: string[];
+    start: string[];
+  }>(
     (acc, startString, index) => {
       if (startString.length > endStrings[index].length) {
         acc.start.push(startString);
@@ -881,10 +884,7 @@ export function getFormattedTimeRangeWithLeadingAndTrailingZero(
       acc.end.push(endStrings[index]);
       return acc;
     },
-    {start: [], end: []} as {
-      end: string[];
-      start: string[];
-    }
+    {start: [], end: []}
   );
 
   return {

+ 11 - 8
static/app/components/replays/utils.tsx

@@ -120,14 +120,17 @@ export function getCrumbsByColumn(
     return [column, breadcrumb] as [number, Crumb];
   });
 
-  const crumbsByColumn = columnCrumbPairs.reduce((map, [column, breadcrumb]) => {
-    if (map.has(column)) {
-      map.get(column)?.push(breadcrumb);
-    } else {
-      map.set(column, [breadcrumb]);
-    }
-    return map;
-  }, new Map() as Map<number, Crumb[]>);
+  const crumbsByColumn = columnCrumbPairs.reduce<Map<number, Crumb[]>>(
+    (map, [column, breadcrumb]) => {
+      if (map.has(column)) {
+        map.get(column)?.push(breadcrumb);
+      } else {
+        map.set(column, [breadcrumb]);
+      }
+      return map;
+    },
+    new Map()
+  );
 
   return crumbsByColumn;
 }

+ 6 - 6
static/app/views/dashboards/widgetBuilder/buildSteps/groupByStep/groupBySelector.tsx

@@ -63,7 +63,10 @@ export function GroupBySelector({fieldOptions, columns = [], onChange}: Props) {
   const columnFieldsAsString = columns.map(generateFieldAsString);
 
   const {filteredFieldOptions, columnsAsFieldOptions} = useMemo(() => {
-    return Object.keys(fieldOptions).reduce(
+    return Object.keys(fieldOptions).reduce<{
+      columnsAsFieldOptions: FieldOptions[];
+      filteredFieldOptions: FieldOptions;
+    }>(
       (acc, key) => {
         const value = fieldOptions[key];
         const optionInColumnsIndex = columnFieldsAsString.findIndex(
@@ -79,18 +82,15 @@ export function GroupBySelector({fieldOptions, columns = [], onChange}: Props) {
       {
         filteredFieldOptions: {},
         columnsAsFieldOptions: [],
-      } as {
-        columnsAsFieldOptions: FieldOptions[];
-        filteredFieldOptions: FieldOptions;
       }
     );
   }, [fieldOptions, columnFieldsAsString]);
 
   const items = useMemo(() => {
-    return columns.reduce((acc, _column, index) => {
+    return columns.reduce<string[]>((acc, _column, index) => {
       acc.push(String(index));
       return acc;
-    }, [] as string[]);
+    }, []);
   }, [columns]);
 
   return (

+ 2 - 2
static/app/views/dashboards/widgetBuilder/utils.tsx

@@ -336,7 +336,7 @@ export function getAmendedFieldOptions({
 
 // Extract metric names from aggregation functions present in the widget queries
 export function getMetricFields(queries: WidgetQuery[]) {
-  return queries.reduce((acc, query) => {
+  return queries.reduce<string[]>((acc, query) => {
     for (const field of [...query.aggregates, ...query.columns]) {
       const fieldParameter = /\(([^)]*)\)/.exec(field)?.[1];
       if (fieldParameter && !acc.includes(fieldParameter)) {
@@ -345,7 +345,7 @@ export function getMetricFields(queries: WidgetQuery[]) {
     }
 
     return acc;
-  }, [] as string[]);
+  }, []);
 }
 
 // Used to limit the number of results of the "filter your results" fields dropdown

+ 2 - 2
static/app/views/releases/detail/overview/sidebar/commitAuthorBreakdown.tsx

@@ -54,7 +54,7 @@ class CommitAuthorBreakdown extends AsyncComponent<Props, State> {
 
   renderBody() {
     // group commits by author
-    const groupedAuthorCommits = this.state.commits?.reduce(
+    const groupedAuthorCommits = this.state.commits?.reduce<GroupedAuthorCommits>(
       (authorCommitsAccumulator, commit) => {
         const email = commit.author?.email ?? 'unknown';
 
@@ -69,7 +69,7 @@ class CommitAuthorBreakdown extends AsyncComponent<Props, State> {
 
         return authorCommitsAccumulator;
       },
-      {} as GroupedAuthorCommits
+      {}
     );
 
     // sort authors by number of commits

+ 2 - 2
static/app/views/releases/list/releasesRequest.tsx

@@ -149,14 +149,14 @@ class ReleasesRequest extends Component<Props, State> {
 
     return {
       query: new MutableSearch(
-        releases.reduce((acc, release, index, allReleases) => {
+        releases.reduce<string[]>((acc, release, index, allReleases) => {
           acc.push(`release:"${release}"`);
           if (index < allReleases.length - 1) {
             acc.push('OR');
           }
 
           return acc;
-        }, [] as string[])
+        }, [])
       ).formatString(),
       interval: getInterval(selection.datetime),
       ...normalizeDateTimeParams(pick(location.query, Object.values(URL_PARAM)), {

+ 2 - 2
static/app/views/settings/organizationIntegrations/integrationExternalTeamMappings.tsx

@@ -90,7 +90,7 @@ class IntegrationExternalTeamMappings extends AsyncComponent<Props, State> {
   get mappings() {
     const {integration} = this.props;
     const {teams} = this.state;
-    const externalTeamMappings = teams.reduce((acc, team) => {
+    const externalTeamMappings = teams.reduce<ExternalActorMapping[]>((acc, team) => {
       const {externalTeams} = team;
       acc.push(
         ...externalTeams
@@ -98,7 +98,7 @@ class IntegrationExternalTeamMappings extends AsyncComponent<Props, State> {
           .map(externalTeam => ({...externalTeam, sentryName: team.slug}))
       );
       return acc;
-    }, [] as ExternalActorMapping[]);
+    }, []);
     return externalTeamMappings.sort((a, b) => parseInt(a.id, 10) - parseInt(b.id, 10));
   }
 

+ 2 - 2
static/app/views/settings/organizationIntegrations/integrationExternalUserMappings.tsx

@@ -74,7 +74,7 @@ class IntegrationExternalUserMappings extends AsyncComponent<Props, State> {
   get mappings() {
     const {integration} = this.props;
     const {members} = this.state;
-    const externalUserMappings = members.reduce((acc, member) => {
+    const externalUserMappings = members.reduce<ExternalActorMapping[]>((acc, member) => {
       const {externalUsers, user} = member;
 
       acc.push(
@@ -83,7 +83,7 @@ class IntegrationExternalUserMappings extends AsyncComponent<Props, State> {
           .map(externalUser => ({...externalUser, sentryName: user?.name ?? member.name}))
       );
       return acc;
-    }, [] as ExternalActorMapping[]);
+    }, []);
     return externalUserMappings.sort((a, b) => parseInt(a.id, 10) - parseInt(b.id, 10));
   }