I am developing a generic function using TypeScript. My function, exampleFunction, accepts multiple props, including data, preSelected, and onSelect.
✅ Problem I Solved By using three different NoInfer implementations, I successfully prevented TypeScript from defaulting all inferred types to any. Now, TData inside the generic component does not collapse into any when preSelected or onSelect is provided incorrectly.
❌ Remaining Issue However, when allowMultipleSelection: true is set, TypeScript does not throw an error, even if preSelected or onSelect are incorrectly typed. I want TypeScript to enforce stricter type checks in this case and throw an error.
TS Playground
interface BaseProps<TData> {
data: TData[];
}
// Multiple selection mode returning the full item
interface MultiSelectModeTypeItem<TData> extends BaseProps<TData> {
returnType: 'item';
allowMultipleSelection: true;
preSelected?: NoInfer<TData[]>; // StrictArray kullan
onSelect?: (selectedItems: NoInfer<TData[]>) => void;
}
// Single selection mode returning the full item
interface SingleSelectModeTypeItem<TData> extends BaseProps<TData> {
returnType: 'item';
allowMultipleSelection: false;
preSelected?: NoInfer<TData>;
onSelect?: (selectedItem: NoInfer<TData>) => void;
}
// Union type for SymbolFilterProps
export type SymbolFilterProps<TData> =
| MultiSelectModeTypeItem<TData>
| SingleSelectModeTypeItem<TData>
// Example data type
type SymbolFilterParams = {
symbol: string;
symbolDesc: string;
};
// Example function to test type enforcement
function exampleFunction<TData>(props: SymbolFilterProps<TData>) {
console.log(props);
}
// Test data
const data: SymbolFilterParams[] = [];
// Incorrect usage for multiple selection (should trigger TypeScript errors)
// Here, 'selectedSymbols' is typed as any[], which is incorrect.
const selectedSymbols = []; // <--- Here is the issue, we are using `any[]` or dont
// A generic onSelect function with any[] or dont as parameter (should trigger error)
const onSelect = (selectedItems) => {
console.log(selectedItems);
};
// --- Correct Usage Examples ---
// Multiple selection mode using full item (expected to throw errors if types are incorrect)
exampleFunction({
returnType: 'item',
allowMultipleSelection: true,
data,
onSelect, // If 'onSelect' is incorrectly typed, TypeScript should error
preSelected: selectedSymbols // This should also error if the type doesn't match
});
// Single selection mode using full item (should be correct if types match)
exampleFunction({
returnType: 'item',
allowMultipleSelection: false,
data,
onSelect,
preSelected: selectedSymbols
});
I think this is the minimal reproducible example I could create to demonstrate the issue:
TS Playground
interface MultiSelectMode<T> {
allowMultipleSelection: true;
preSelected?: NoInfer<T>[];
onSelect?: (selectedItems: NoInfer<T>[]) => void;
}
interface SingleSelectMode<T> {
allowMultipleSelection: false;
preSelected?: NoInfer<T>;
onSelect?: (selectedItem: NoInfer<T>) => void;
}
type Data<T> = { data: T[] }
type Props<T> = (MultiSelectMode<T> | SingleSelectMode<T>) & Data<T>;
type DataProps = { symbolCode: string, symbolDesc: string };
const exampleFunc = <T,>(props: Props<T>) => { }
const selectedSymbols: any[] = [];
const onSelect = (selectedItems: any[]) => { };
const data: DataProps[] = []
exampleFunc({ data, allowMultipleSelection: true, onSelect, preSelected: selectedSymbols })
exampleFunc({ data, allowMultipleSelection: false, onSelect, preSelected: selectedSymbols })
Problem Clarification any[] Assignment Issue:
Here, selectedSymbols is being declared as any[]. Since TypeScript defaults untyped props to any[], it silently bypasses type checking and doesn’t enforce the correct type on preSelected or onSelect.
Expectation: I expect TypeScript to throw an error when any[] is passed, even in multiple selection mode (allowMultipleSelection: true).
Current Behavior: TypeScript does not enforce the type checks when allowMultipleSelection: true and allows any[] to propagate.
Expected Behavior: I want TypeScript to:
- Throw an error if preSelected = [] is passed without a correct type.
- Throw an error if onSelect = selectedItems => {} is used without specifying the correct type.
- Ensure TypeScript does not infer TData = any in any scenario.
Goal:
The goal is to ensure that when allowMultipleSelection: true, TypeScript enforces stricter type checks on preSelected and onSelect, just like it does for single selection mode (allowMultipleSelection: false).
I am developing a generic function using TypeScript. My function, exampleFunction, accepts multiple props, including data, preSelected, and onSelect.
✅ Problem I Solved By using three different NoInfer implementations, I successfully prevented TypeScript from defaulting all inferred types to any. Now, TData inside the generic component does not collapse into any when preSelected or onSelect is provided incorrectly.
❌ Remaining Issue However, when allowMultipleSelection: true is set, TypeScript does not throw an error, even if preSelected or onSelect are incorrectly typed. I want TypeScript to enforce stricter type checks in this case and throw an error.
TS Playground
interface BaseProps<TData> {
data: TData[];
}
// Multiple selection mode returning the full item
interface MultiSelectModeTypeItem<TData> extends BaseProps<TData> {
returnType: 'item';
allowMultipleSelection: true;
preSelected?: NoInfer<TData[]>; // StrictArray kullan
onSelect?: (selectedItems: NoInfer<TData[]>) => void;
}
// Single selection mode returning the full item
interface SingleSelectModeTypeItem<TData> extends BaseProps<TData> {
returnType: 'item';
allowMultipleSelection: false;
preSelected?: NoInfer<TData>;
onSelect?: (selectedItem: NoInfer<TData>) => void;
}
// Union type for SymbolFilterProps
export type SymbolFilterProps<TData> =
| MultiSelectModeTypeItem<TData>
| SingleSelectModeTypeItem<TData>
// Example data type
type SymbolFilterParams = {
symbol: string;
symbolDesc: string;
};
// Example function to test type enforcement
function exampleFunction<TData>(props: SymbolFilterProps<TData>) {
console.log(props);
}
// Test data
const data: SymbolFilterParams[] = [];
// Incorrect usage for multiple selection (should trigger TypeScript errors)
// Here, 'selectedSymbols' is typed as any[], which is incorrect.
const selectedSymbols = []; // <--- Here is the issue, we are using `any[]` or dont
// A generic onSelect function with any[] or dont as parameter (should trigger error)
const onSelect = (selectedItems) => {
console.log(selectedItems);
};
// --- Correct Usage Examples ---
// Multiple selection mode using full item (expected to throw errors if types are incorrect)
exampleFunction({
returnType: 'item',
allowMultipleSelection: true,
data,
onSelect, // If 'onSelect' is incorrectly typed, TypeScript should error
preSelected: selectedSymbols // This should also error if the type doesn't match
});
// Single selection mode using full item (should be correct if types match)
exampleFunction({
returnType: 'item',
allowMultipleSelection: false,
data,
onSelect,
preSelected: selectedSymbols
});
I think this is the minimal reproducible example I could create to demonstrate the issue:
TS Playground
interface MultiSelectMode<T> {
allowMultipleSelection: true;
preSelected?: NoInfer<T>[];
onSelect?: (selectedItems: NoInfer<T>[]) => void;
}
interface SingleSelectMode<T> {
allowMultipleSelection: false;
preSelected?: NoInfer<T>;
onSelect?: (selectedItem: NoInfer<T>) => void;
}
type Data<T> = { data: T[] }
type Props<T> = (MultiSelectMode<T> | SingleSelectMode<T>) & Data<T>;
type DataProps = { symbolCode: string, symbolDesc: string };
const exampleFunc = <T,>(props: Props<T>) => { }
const selectedSymbols: any[] = [];
const onSelect = (selectedItems: any[]) => { };
const data: DataProps[] = []
exampleFunc({ data, allowMultipleSelection: true, onSelect, preSelected: selectedSymbols })
exampleFunc({ data, allowMultipleSelection: false, onSelect, preSelected: selectedSymbols })
Problem Clarification any[] Assignment Issue:
Here, selectedSymbols is being declared as any[]. Since TypeScript defaults untyped props to any[], it silently bypasses type checking and doesn’t enforce the correct type on preSelected or onSelect.
Expectation: I expect TypeScript to throw an error when any[] is passed, even in multiple selection mode (allowMultipleSelection: true).
Current Behavior: TypeScript does not enforce the type checks when allowMultipleSelection: true and allows any[] to propagate.
Expected Behavior: I want TypeScript to:
- Throw an error if preSelected = [] is passed without a correct type.
- Throw an error if onSelect = selectedItems => {} is used without specifying the correct type.
- Ensure TypeScript does not infer TData = any in any scenario.
Goal:
The goal is to ensure that when allowMultipleSelection: true, TypeScript enforces stricter type checks on preSelected and onSelect, just like it does for single selection mode (allowMultipleSelection: false).
Share Improve this question edited Feb 15 at 22:44 Okay Beydanol asked Feb 15 at 10:56 Okay BeydanolOkay Beydanol 517 bronze badges 15 | Show 10 more comments1 Answer
Reset to default 1I want TypeScript to enforce stricter type checks in this case and throw an error
That's not something reasonably easy to do in TypeScript alone - nor should it be. any
and any[]
are completely valid types in TypeScript. Their intended purpose is to let developers work with not-completely-typed data. They're intentional "escape hatches" for the type system.
To avoid any
s in nuanced code, two strategies you'll find useful are:
- Don't declare evolving or implicit
any
s - Lint to prevent accidental uses of
any
s
Don't declare evolving or implicit any
s to begin with
Note that the two terms are different:
- Evolving
any
s are when a value starts without an inferable type but can be narrowed over time: https://effectivetypescript/2020/03/09/evolving-any - Implicit
any
s are when a value can't have a better type inferred from its initial declaration and can't be evolved over time: https://www.totaltypescript/concepts/parameter-x-implicitly-has-an-any-type
In the snippets in the OP and the comments underneath it, you have two main examples of this:
- Evolving
any
: theconst selectedSymbols = [];
- This one also counts as an implicit
any
because it's used in ways later on (an argument to a generic type parameter) that TypeScript can't reasonably infer a type from
- This one also counts as an implicit
- Implicit
any
: theconst onSelect = (selectedItems) => {
TypeScript's noImplicitAny
compiler option is already reporting type errors on them in the playground. Good!
Lint to prevent accidental uses of anys
Even with noImplicitAny enabled, you may sometimes find cases of the any
type getting introduced into code. Lint rules such as those in typescript-eslint's recommended
config and recommendedTypeChecked
config can catch those.
A couple that are commonly useful:
@typescript-eslint/no-explicit-any
: reports on explicit uses of theany
type@typescript-eslint/no-unsafe-argument
: reports on passing anany
-typed value as an argument to a parameter that doesn't acceptany
See https://typescript-eslint.io/blog/avoiding-anys for more avoiding any
s with typescript-eslint.
any[]
and then getting unhappy when it is assignable tostring[]
? But that's just how theany
type works. It is intentionally unsafe, and if you use it, you're intentionally loosening the safety. No matter how you write your function,const foo: string[] = selectedSymbols
will be allowed, so it's not even solvable in principle. If your issue is withany
then maybe you want a linter rule to try to preventany
completely? Please edit to clarify and explain how we can proceed. – jcalz Commented Feb 15 at 16:40any[]
coming from? Either this isn’t a minimal reproducible example or I just don’t understand your issue or both. Please edit the question to clarify. – jcalz Commented Feb 15 at 17:02