Can I be notified when I use a third-party function that returns (some variant of) any
? (via a compiler error/warning, linter message, anything really...)
Motivating case: despite using tsc --noImplicitAny
and eslint
with @typescript-eslint/no-explicit-any
, I did not know I was using a variable with type any
.
I have some external data that boils down to:
interface T1 {
name: string
color: string
}
interface T2 {
id: string
}
interface T3 {
name: string
height: number
}
interface Data {
k1: {[key: string]: T1}
k2: {[key: string]: T2}
k3: {[key: string]: T3}
}
And, because T1
and T3
have something in common, I want to do the same operation on both:
function f(data: Data) {
for (const key of ['k1', 'k3'] as const) {
for (const v of Object.values(data[key])) {
console.log(v.name)
}
}
}
Object.values
has two overloads. My code evolved from using the type-safe one (Object.values<T>(o: {[s: string]: T}): T[]
) to the version above, using the unsafe one (Object.values(o: {}): any[]
) without me noticing, so I did not realize that v
had type any
until it was too late...
Of course there are tons of ways to refactor this code to make it type-safe. My question really is how to detect that it's not type-safe in the first place. Also my question is not about only Object.values
but about any function that can return a variant of any
.
I believe my question differs from How to prevent "any" from being used in TypeScript types and interfaces because I don't have the word "any
" anywhere in my code, so the situation I'm describing is even more tricky.
As far as I can tell there is no single compiler setting or linter rule that completely banishes the any
type. But it does look there is a set of settings and rules that, together, have this effect (or close to it). See Avoiding any
s with Linting and TypeScript for more information. You might want to enable all of these:
TypeScript's --noImplicitAny
compiler setting will warn you if any
appears as the result of a failure/fallback in the TypeScript language itself.
@typescript-eslint/no-explicit-any
will warn you if any
explicitly appears inside your code as an annotated type.
@typescript-eslint/no-unsafe-argument
will warn you if you call a function with an argument of type any
.
@typescript-eslint/no-unsafe-assignment
will warn you if you assign a value of type any
to a variable or property.
@typescript-eslint/no-unsafe-call
will warn you if you call a value of type any
like a function.
@typescript-eslint/no-unsafe-member-access
will warn you if you index into a value of type any
.
@typescript-eslint/no-unsafe-return
will warn you if you call a function that returns any
.
There are other linter rules that avoid various unsafe things, but these should cover most cases.
Of course if you do enable these you can expect lots of warnings all over the place, because whether we like it or not, any
appears quite often in TypeScript's libraries. The longstanding feature request at microsoft/TypeScript#26188 to replace such any
s with safe versions like unknown
or never
(depending on variance, see Difference between Variance, Covariance, Contravariance, Bivariance and Invariance in TypeScript) has not been implemented because it really breaks a lot of things and is harder for developers to reason about (see microsoft/TypeScript#24737). For those serious about excising any
entirely, or only manually allowing it in specific places in the code, this might still be a reasonable course of action. For everyone else, it might not be worth the hassle.