Skip to content

Commit f7f12ee

Browse files
authored
fix: Replace raw "in" operator checks with type guards in property-filter (#4304)
1 parent e16f6f9 commit f7f12ee

File tree

5 files changed

+37
-9
lines changed

5 files changed

+37
-9
lines changed

src/property-filter/controller.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
TokenGroup,
2222
} from './interfaces';
2323
import {
24+
isInternalToken,
2425
matchFilteringProperty,
2526
matchOperator,
2627
matchOperatorPrefix,
@@ -46,7 +47,7 @@ export const getQueryActions = ({
4647
}) => {
4748
const setQuery = (query: InternalQuery) => {
4849
function transformToken(token: InternalToken | InternalTokenGroup): Token | TokenGroup {
49-
if ('operator' in token) {
50+
if (isInternalToken(token)) {
5051
return matchTokenValue(token, filteringOptions);
5152
}
5253
return { ...token, tokens: token.tokens.map(transformToken) };

src/property-filter/filter-options.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export function filterOptions(
2727
}
2828

2929
function isGroup(optionOrGroup: AutosuggestProps.Option): optionOrGroup is AutosuggestProps.OptionGroup {
30-
return 'options' in optionOrGroup;
30+
const key: keyof AutosuggestProps.OptionGroup = 'options';
31+
return key in optionOrGroup;
3132
}
3233

3334
function matchSingleOption(option: OptionDefinition, searchText: string): boolean {

src/property-filter/internal.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,11 @@ const PropertyFilterInternal = React.forwardRef(
161161
tokenOrGroup: Token | TokenGroup,
162162
standaloneIndex?: number
163163
): InternalToken | InternalTokenGroup {
164-
return 'operation' in tokenOrGroup
164+
const isTokenGroup = (t: Token | TokenGroup): t is TokenGroup => {
165+
const key: keyof TokenGroup = 'operation';
166+
return key in t;
167+
};
168+
return isTokenGroup(tokenOrGroup)
165169
? {
166170
operation: tokenOrGroup.operation,
167171
tokens: tokenOrGroup.tokens.map(token => transformToken(token)),

src/property-filter/token.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
LoadItemsDetail,
2424
} from './interfaces';
2525
import { TokenEditor } from './token-editor';
26-
import { tokenGroupToTokens } from './utils';
26+
import { isInternalToken, isInternalTokenGroup, tokenGroupToTokens } from './utils';
2727

2828
import analyticsSelectors from './analytics-metadata/styles.css.js';
2929
import styles from './styles.css.js';
@@ -71,20 +71,24 @@ export const TokenButton = ({
7171
}: TokenProps) => {
7272
const tokenRef = useRef<FilteringTokenRef>(null);
7373

74-
const hasGroups = query.tokens.some(tokenOrGroup => 'operation' in tokenOrGroup);
74+
const hasGroups = query.tokens.some(isInternalTokenGroup);
7575
const first = tokenIndex === 0;
7676

7777
const tokenOrGroup = query.tokens[tokenIndex];
7878
const tokens = tokenGroupToTokens<InternalToken>([tokenOrGroup]).map(t => ({ ...t, standaloneIndex: undefined }));
7979
const operation = query.operation;
80-
const groupOperation = 'operation' in tokenOrGroup ? tokenOrGroup.operation : operation === 'and' ? 'or' : 'and';
80+
const groupOperation = isInternalTokenGroup(tokenOrGroup)
81+
? tokenOrGroup.operation
82+
: operation === 'and'
83+
? 'or'
84+
: 'and';
8185

8286
const [tempTokens, setTempTokens] = useState<InternalToken[]>(tokens);
8387
const capturedTokenIndices = tempTokens.map(token => token.standaloneIndex).filter(index => index !== undefined);
8488
const tokensToCapture: InternalToken[] = [];
8589
for (let index = 0; index < query.tokens.length; index++) {
8690
const token = query.tokens[index];
87-
if ('operator' in token && token !== tokenOrGroup && !capturedTokenIndices.includes(index)) {
91+
if (isInternalToken(token) && token !== tokenOrGroup && !capturedTokenIndices.includes(index)) {
8892
tokensToCapture.push(token);
8993
}
9094
}

src/property-filter/utils.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,22 @@ import {
66
InternalFilteringOption,
77
InternalFilteringProperty,
88
InternalToken,
9+
InternalTokenGroup,
910
Token,
1011
} from './interfaces';
1112

13+
export function isInternalToken(tokenOrGroup: InternalToken | InternalTokenGroup): tokenOrGroup is InternalToken {
14+
const key: keyof InternalToken = 'operator';
15+
return key in tokenOrGroup;
16+
}
17+
18+
export function isInternalTokenGroup(
19+
tokenOrGroup: InternalToken | InternalTokenGroup
20+
): tokenOrGroup is InternalTokenGroup {
21+
const key: keyof InternalTokenGroup = 'operation';
22+
return key in tokenOrGroup;
23+
}
24+
1225
// Finds the longest property the filtering text starts from.
1326
export function matchFilteringProperty(
1427
filteringProperties: readonly InternalFilteringProperty[],
@@ -137,17 +150,22 @@ interface AbstractTokenGroup<T extends AbstractToken> {
137150
tokens: readonly (T | AbstractTokenGroup<T>)[];
138151
}
139152

153+
function isAbstractToken<T extends AbstractToken>(tokenOrGroup: T | AbstractTokenGroup<T>): tokenOrGroup is T {
154+
const key: keyof AbstractToken = 'operator';
155+
return key in tokenOrGroup;
156+
}
157+
140158
/**
141159
* Transforms query token groups to tokens (only taking 1 level of nesting).
142160
*/
143161
export function tokenGroupToTokens<T extends AbstractToken>(tokenGroups: readonly (T | AbstractTokenGroup<T>)[]): T[] {
144162
const tokens: T[] = [];
145163
for (const tokenOrGroup of tokenGroups) {
146-
if ('operator' in tokenOrGroup) {
164+
if (isAbstractToken(tokenOrGroup)) {
147165
tokens.push(tokenOrGroup);
148166
} else {
149167
for (const nestedTokenOrGroup of tokenOrGroup.tokens) {
150-
if ('operator' in nestedTokenOrGroup) {
168+
if (isAbstractToken(nestedTokenOrGroup)) {
151169
tokens.push(nestedTokenOrGroup);
152170
} else {
153171
// Ignore deeply nested tokens

0 commit comments

Comments
 (0)