Description
Before You File a Proposal Please Confirm You Have Done The Following...
- I have searched for related issues and found none that match my proposal.
- I have searched the current rule list and found no rules that match my proposal.
- I have read the FAQ and my problem is not listed.
My proposal is suitable for this project
- I believe my proposal would be useful to the broader TypeScript community (meaning it is not a niche proposal).
Link to the rule's documentation
https://typescript-eslint.io/rules/ban-types/
Description
The rule forbids the use of the type {}
(and its synonym Object
), which means "any non-nullish value", and gives some helpful suggestions on what to use instead, depending on what the developer actually might have meant.
However, there seems to be no suggestion (outside disabling the rule) for what to use when the intended meaning really is "any non-nullish value". The suggested alternative for "any object", namely object
, doesn't include primitive types such as number
, so it's not an equivalent replacement in this case.
Rather than bypassing or disabling the rule, and leaving the easily misunderstood {}
in place, I think it would be useful to suggest an explicit alternative for this case as well; something along the lines of
- If you really want a type meaning "any non-nullish value", you probably want `NonNullable<unknown>` instead.
(placed after all the other suggestions).
TypeScript includes the NonNullable
utility type since 2.8, so I don't think there shouldn't be any compatibility issues.
PS: I wasn't sure if this issue should go under Documentation or Enhancement; since it changes the output of the rule I opted for the latter. My apologies if I got it wrong :)
Fail
/**
* This is a generic combinator to add a fallback value to a function, to handle a null input.
* However, we don't want to accidentally use it when the function _already_ handles null,
* otherwise our fallback will clobber the original value.
*/
const withFallback: <Input extends {}, Output>( // This fails the rule and that's OK :)
mapping: (input: Input) => Output,
fallback: Output
) => (input: Input | null) => Output = (mapping, fallback) => (input) =>
input === null ? fallback : mapping(input);
const plusOne: (input: number) => number
const plusOneWithFallback = withFallback(plusOne, 0); // This won't compile if we replace {} with object
Pass
const withFallback: <Input extends NonNullable<unknown>, Output>( // Same meaning, explicit, passes :)
mapping: (input: Input) => Output,
fallback: Output
) => (input: Input | null) => Output = (mapping, fallback) => (input) =>
input === null ? fallback : mapping(input);
const plusOne: (input: number) => number
const plusOneWithFallback = withFallback(plusOne, 0); // This compiles
Additional Info
No response