import parser from '@typescript-eslint/parser'; import { RuleTester } from '@typescript-eslint/rule-tester'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import dedent from 'dedent'; import { noHiddenTypeAssertions } from './no-hidden-type-assertions.mjs'; const ruleTester = new RuleTester({ languageOptions: { parserOptions: { sourceType: 'module', project: './tsconfig.tests.json', }, parser, }, }); ruleTester.run('no-hidden-type-assertions', noHiddenTypeAssertions, { valid: [ // No call signature { filename: 'file.ts', code: dedent` foo() `, }, // Hidden type assertion but set to `unknown` { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: string) => Promise; } declare const axios: Axios; export const result: Promise = axios.request("hello"); `, }, // Hidden type assertion but set to `never` { filename: 'file.ts', code: dedent` declare class Axios { readonly request: () => Promise; } declare const axios: Axios; export const result = axios.request(); `, }, // Generic used in input value, explicitly provided { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: T) => T; } declare const axios: Axios; export const result: string = axios.request("hello"); `, }, // Generic used in input value, not explicitly provided { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: T) => Promise; } declare const axios: Axios; export const result = axios.request("hello"); `, }, // Generic used in input value, not explicitly provided, no default { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: T) => Promise; } declare const axios: Axios; export const result = axios.request("hello"); `, }, // No generic { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: string) => Promise; } declare const axios: Axios; export const result: Promise = axios.request("hello"); `, }, // Reused generic name { filename: 'file.ts', code: dedent` declare const foo: ( a: string, b: T ) => typeof a extends (infer T)[] ? T : typeof a; export const result = foo("hello", "world"); `, }, // function type parameter { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: () => T) => Promise; } declare const axios: Axios; export const result = axios.request(() => "hello"); `, }, // chainFirstIOK { filename: 'file.ts', code: dedent` declare const chainFirstIOK: ( f: (a: A) => Promise ) => (first: Promise) => Promise; export const result = chainFirstIOK(() => Promise.resolve(true) ); `, }, // object literal type hidden type assertion but set to unknown { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: string) => { t: T }; } declare const axios: Axios; export const result = axios.request("hello"); `, }, // type param has default set to never { filename: 'file.ts', code: dedent` declare const right: (a: A) => E | A; export const result = right("hello"); `, }, // toArray { filename: 'file.ts', code: dedent` export declare const toArray: (val: readonly A[]) => A[]; const ra = [""] as const; export const result = toArray(ra); `, }, ], invalid: [ // Hidden type assertion set to arbitrary type { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: string) => Promise; } declare const axios: Axios; export const result: Promise = axios.request("hello"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // Hidden type assertion set to parameter type coincidentally { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: string) => Promise; } declare const axios: Axios; export const result: Promise = axios.request("hello"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: string) => T; } declare const axios: Axios; export const result: boolean = axios.request("hello"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // index into type { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: string) => Promise; } declare const axios: Axios; export const result = axios.request("hello"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // conditional type { filename: 'file.ts', code: dedent` declare class Axios { readonly request: ( url: string ) => T extends 42 ? 43 : 45; } declare const axios: Axios; export const result = axios.request<"asdf">("hello"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // object literal type { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: string) => { t: { t2: T } }; } declare const axios: Axios; export const result = axios.request("hello"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // tuple { filename: 'file.ts', code: dedent` declare class Axios { readonly request: (url: string) => { t: [T] }; } declare const axios: Axios; export const result = axios.request("hello"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, ], } as const);