-
Notifications
You must be signed in to change notification settings - Fork 13k
Description
π Search Terms
implicit any containers
β Viability Checklist
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
β Suggestion
Currently, new Map()
has type Map<any, any>
and new Set()
has type Set<any>
. I suggest to add an option so that instead new Map()
has type Map<never, never>
and new Set()
has type Set<never>
. This should work because Set<never>
is assignable to any other set type, and same for maps.
Note that this needs to be an option, otherwise it could break existing code.
π Motivating Example
I ran into this issue with code similar to the following:
declare function returnsNullableMap(): Map<number, number> | null;
const myMap = returnsNullableMap() ?? new Map();
myMap.set("", ""); //This compiles but shouldn't
The last line is obviously a mistake since the map contains numbers, not strings. But since new Map()
has type Map<any, any>
, so does myMap
, and the last line compiles.
π» Use Cases
- What do you want to use this for?
I would like to completely avoid the any
type in my code, and the fact that the code above actually does contain any
is not immediately obvious. I use existing options such as noImplicitAny
and useUnknownInCatchVariables
to avoid any
sneaking in at other places, but apparently any
can still sneak in in this case. By the way, I would have expected noImplicitAny
to cover this case as well, but apparently it doesn't.
- What workarounds are you using in the meantime?
In the specific code above I can use const myMap = returnsNullableMap() ?? new Map<never, never>();
and it works fine, myMap
has the correct type (Map<number, number>
). Note that in my actual code my types are much more complicated than just number
, so using never
saves a lot of typing compared to using the actual type. In this simplified example however new Map<number, number>()
would have worked just as well.
- What shortcomings exist with current approaches?
The main issue is that if I forget the <never, never>
(or a similar workaround), my code will contain the any
type without making it immediately obvious, allowing mistakes like in the example above. Another minor annoyance is that new Map<never, never>()
is more verbose than just new Map()
, but I can live with that, what I'm more concerned about is any
types sneaking into my code where I don't want them.