Reputation: 51
For example, the function JSON.parse(data)
returns a type of any
. So if you write something like this:
const parsed = JSON.parse('example');
console.log(parsed.somethingThatDoesntExist);
No error occurs in VSCode, despite having noImplicitAny
set to true
in my tsconfig.json
, and my .eslintrc.js
having the rule '@typescript-eslint/no-explicit-any': 'error'
.
I have also tried adding the following rules to my eslintrc.js
, however they seem to break all TypeScript error checking:
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-argument': 'error',
'@typescript-eslint/no-unsafe-assignment': 'error',
In an ideal world I would want this any
to be presumed to be unknown
, but an error would also be great.
Here is my eslintrc.js
:
module.exports = exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
ecmaVersion: 2021,
},
extends: ['plugin:@typescript-eslint/recommended', 'prettier', 'plugin:prettier/recommended'],
rules: {
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-argument': 'error',
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'prettier/prettier': [
'error',
{
trailingComma: 'all',
tabWidth: 2,
semi: true,
singleQuote: true,
bracketSpacing: true,
printWidth: 120,
endOfLine: 'auto',
},
],
},
};
and tsconfig.json
:
{
"compilerOptions": {
"strict": true,
"target": "es6",
"module": "commonjs",
"lib": [
"es6",
"ES2021.String"
],
"esModuleInterop": true,
"moduleResolution": "node",
"outDir": "../build/",
"rootDir": ".",
"resolveJsonModule": true,
"composite": true,
"types": [],
"noImplicitAny": true,
"noImplicitThis": true,
"noImplicitReturns": true
}
}
Upvotes: 5
Views: 528
Reputation: 33627
Unfortunately, I don't know of a compiler option or similarly global solution that gives the result you want. However, you can craft an assertion function that disallows any
on a specific expression:
type NotAny<T> = 0 extends 1 & T ? never : unknown
declare function assertNotAny<T extends NotAny<T>>(value: T): void
assertNotAny('"example"') // okay
assertNotAny(JSON.parse('"example"')) // error
This uses the fact that any
cannot be assigned to never
. By making a conditional type that resolves to never
, you can cause a type error when any
is passed in.
For more details, see https://stackoverflow.com/a/77385024/480608
Upvotes: 0
Reputation: 2472
I think your best option would be to override any libraries where you want an explicit type. Generally the built-ins are typed well (with the exception of JSON.parse), but this could be helpful if you want to fix a broken or stubbed type from an external library.
For global (or built-ins) in a global.d.ts
declare global {
interface JSON {
parse<T>(text: string, reviver?: (this: any, key: string, value: any) => T): T
}
}
export {} //this is needed to make it a module
Or a different syntax for modules
declare module 'fooLibrary' {
declare function bar<T>(): T
}
// IE. require('fooLibrary') or import * from ('fooLibrary')
And now when you try to use JSON.parse
const foo = JSON.parse('test');
// ^type? => unknown
const bar = JSON.parse<Record<string, any>>(...);
// ^type? => Record<string, any>
View working example on TS Playground
Upvotes: 1