Skip to content

Commit 9b66ba8

Browse files
committed
Fix TypeScript type mismatches and reduce duplication
- Replace enums with string literal union types for MetricAggregation, OperationType, and MatchType - Eliminate code duplication by using single mapping objects for options - Improve type safety for GA4 API request builder
1 parent 8776698 commit 9b66ba8

5 files changed

Lines changed: 46 additions & 69 deletions

File tree

src/components/ga4/QueryExplorer/BasicReport/useMakeRequest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ const useMakeRequest = ({
123123
r.keepEmptyRows = keepEmptyRows
124124
}
125125
if (metricAggregations !== undefined && metricAggregations.length !== 0) {
126-
r.metricAggregations = metricAggregations
126+
r.metricAggregations = metricAggregations as any
127127
}
128128
return r
129129
}, [

src/components/ga4/QueryExplorer/Filter/Filter/NumericFilter.tsx

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,19 @@ interface NumericFilterProps {
1313
path: ExpressionPath
1414
}
1515

16-
export enum OperationType {
17-
Equal = "EQUAL",
18-
LessThan = "LESS_THAN",
19-
LessThanOrEqual = "LESS_THAN_OR_EQUAL",
20-
GreaterThan = "GREATER_THAN",
21-
GreaterThanOrEqual = "GREATER_THAN_OR_EQUAL",
22-
}
16+
export type OperationType = "EQUAL" | "LESS_THAN" | "LESS_THAN_OR_EQUAL" | "GREATER_THAN" | "GREATER_THAN_OR_EQUAL"
2317

24-
const optionFor = (type: OperationType | undefined): SelectOption => {
25-
switch (type) {
26-
case OperationType.GreaterThan:
27-
return { value: type, displayName: ">" }
28-
case OperationType.GreaterThanOrEqual:
29-
return { value: type, displayName: ">=" }
30-
case OperationType.Equal:
31-
return { value: type, displayName: "==" }
32-
case OperationType.LessThan:
33-
return { value: type, displayName: "<" }
34-
case OperationType.LessThanOrEqual:
35-
return { value: type, displayName: "<=" }
36-
default:
37-
return { value: "", displayName: "" }
38-
}
18+
const operationTypeOptions: Record<OperationType, SelectOption> = {
19+
"EQUAL": { value: "EQUAL", displayName: "==" },
20+
"LESS_THAN": { value: "LESS_THAN", displayName: "<" },
21+
"LESS_THAN_OR_EQUAL": { value: "LESS_THAN_OR_EQUAL", displayName: "<=" },
22+
"GREATER_THAN": { value: "GREATER_THAN", displayName: ">" },
23+
"GREATER_THAN_OR_EQUAL": { value: "GREATER_THAN_OR_EQUAL", displayName: ">=" },
3924
}
4025

26+
const optionFor = (type: OperationType | undefined): SelectOption =>
27+
type === undefined ? { value: "", displayName: "" } : operationTypeOptions[type]
28+
4129
type NumericValue = gapi.client.analyticsdata.NumericValue
4230

4331
export const numericValueEquals = (
@@ -67,7 +55,7 @@ export const toNumericValue = (s: string) => {
6755
return nuVal
6856
}
6957

70-
const operationOptions = Object.values(OperationType).map(optionFor)
58+
const operationOptions = Object.values(operationTypeOptions)
7159

7260
// TODO instead of having a filter type drop down, include `between` here and do
7361
// the smarts to choose the right subtype correctly.
@@ -106,7 +94,10 @@ const NumericFilter: React.FC<NumericFilterProps> = ({
10694
value={optionFor(numericFilter.operation as OperationType | undefined)}
10795
label="operation"
10896
onChange={option => {
109-
updateNumericFilter(old => ({ ...old, operation: option?.value }))
97+
updateNumericFilter(old => ({
98+
...old,
99+
operation: option?.value as OperationType | undefined,
100+
}))
110101
}}
111102
options={operationOptions}
112103
/>

src/components/ga4/QueryExplorer/Filter/Filter/StringFilter.tsx

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,7 @@ import Select, { SelectOption } from "@/components/Select"
66
import LabeledCheckbox from "@/components/LabeledCheckbox"
77
import { UpdateFilterFn, ExpressionPath } from "../index"
88

9-
export enum MatchType {
10-
Exact = "EXACT",
11-
BeginsWith = "BEGINS_WITH",
12-
EndsWith = "ENDS_WITH",
13-
Contains = "CONTAINS",
14-
FullRegexp = "FULL_REGEXP",
15-
PartialRegexp = "PARTIAL_REGEXP",
16-
}
9+
export type MatchType = "EXACT" | "BEGINS_WITH" | "ENDS_WITH" | "CONTAINS" | "FULL_REGEXP" | "PARTIAL_REGEXP"
1710

1811
type SFilter = gapi.client.analyticsdata.StringFilter
1912

@@ -23,26 +16,19 @@ interface StringFilterProps {
2316
path: ExpressionPath
2417
}
2518

26-
const optionFor = (type: MatchType | undefined): SelectOption => {
27-
switch (type) {
28-
case MatchType.Exact:
29-
return { value: type, displayName: "exact" }
30-
case MatchType.BeginsWith:
31-
return { value: type, displayName: "begins with" }
32-
case MatchType.EndsWith:
33-
return { value: type, displayName: "ends with" }
34-
case MatchType.Contains:
35-
return { value: type, displayName: "contains" }
36-
case MatchType.FullRegexp:
37-
return { value: type, displayName: "regexp" }
38-
case MatchType.PartialRegexp:
39-
return { value: type, displayName: "partial regexp" }
40-
default:
41-
return { value: "", displayName: "" }
42-
}
19+
const matchTypeOptions: Record<MatchType, SelectOption> = {
20+
"EXACT": { value: "EXACT", displayName: "exact" },
21+
"BEGINS_WITH": { value: "BEGINS_WITH", displayName: "begins with" },
22+
"ENDS_WITH": { value: "ENDS_WITH", displayName: "ends with" },
23+
"CONTAINS": { value: "CONTAINS", displayName: "contains" },
24+
"FULL_REGEXP": { value: "FULL_REGEXP", displayName: "regexp" },
25+
"PARTIAL_REGEXP": { value: "PARTIAL_REGEXP", displayName: "partial regexp" },
4326
}
4427

45-
const matchOptions = Object.values(MatchType).map(optionFor)
28+
const optionFor = (type: MatchType | undefined): SelectOption =>
29+
type === undefined ? { value: "", displayName: "" } : matchTypeOptions[type]
30+
31+
const matchOptions = Object.values(matchTypeOptions)
4632

4733
const StringFilter: React.FC<StringFilterProps> = ({
4834
stringFilter,
@@ -68,7 +54,10 @@ const StringFilter: React.FC<StringFilterProps> = ({
6854
label="match type"
6955
value={matchValue}
7056
onChange={nu => {
71-
updateStringFilter(old => ({ ...old, matchType: nu?.value }))
57+
updateStringFilter(old => ({
58+
...old,
59+
matchType: nu?.value as MatchType | undefined,
60+
}))
7261
}}
7362
options={matchOptions}
7463
/>
@@ -79,7 +68,7 @@ const StringFilter: React.FC<StringFilterProps> = ({
7968
label="value"
8069
onChange={e => {
8170
const nu = e.target.value
82-
updateStringFilter(old => ({ ...old, value: nu }))
71+
updateStringFilter((old: any) => ({ ...old, value: nu }))
8372
}}
8473
/>
8574
<LabeledCheckbox

src/components/ga4/QueryExplorer/Filter/Filter/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,10 @@ const Filter: React.FC<{
174174
}
175175
const value = {} as { operation?: OperationType, matchType?: MatchType}
176176
if (nu.value === "numericFilter") {
177-
value["operation"] = OperationType.Equal
177+
value["operation"] = "EQUAL"
178178
}
179179
if (nu.value === "stringFilter") {
180-
value["matchType"] = MatchType.Exact
180+
value["matchType"] = "EXACT"
181181
}
182182
updateFilter(path, old => ({
183183
fieldName: old.fieldName,

src/components/ga4/QueryExplorer/MetricAggregations.tsx

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,34 +24,31 @@ const StyledWithHelpText = styled(WithHelpText)((
2424
}
2525
}));
2626

27-
export enum MetricAggregation {
28-
Total = "TOTAL",
29-
Minimum = "MINIMUM",
30-
Maximum = "MAXIMUM",
31-
Count = "COUNT",
32-
}
27+
export type MetricAggregation = "TOTAL" | "MINIMUM" | "MAXIMUM" | "COUNT"
3328

34-
const totalOption = { value: MetricAggregation.Total, displayName: "total" }
29+
const totalOption = { value: "TOTAL", displayName: "total" }
3530
const minimumOption = {
36-
value: MetricAggregation.Minimum,
31+
value: "MINIMUM",
3732
displayName: "minimum",
3833
}
3934
const maximumOption = {
40-
value: MetricAggregation.Maximum,
35+
value: "MAXIMUM",
4136
displayName: "maximum",
4237
}
43-
const countOption = { value: MetricAggregation.Count, displayName: "count" }
38+
const countOption = { value: "COUNT", displayName: "count" }
4439

4540
const metricAggregationFor = (aggregation: MetricAggregation): SelectOption => {
4641
switch (aggregation) {
47-
case MetricAggregation.Total:
42+
case "TOTAL":
4843
return totalOption
49-
case MetricAggregation.Minimum:
44+
case "MINIMUM":
5045
return minimumOption
51-
case MetricAggregation.Maximum:
46+
case "MAXIMUM":
5247
return maximumOption
53-
case MetricAggregation.Count:
48+
case "COUNT":
5449
return countOption
50+
default:
51+
return { value: "", displayName: "" }
5552
}
5653
}
5754

0 commit comments

Comments
 (0)