Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unreleased

- Reject malformed `--min-coverage` values instead of accepting numeric prefixes.
- Classify weak types in constructor signature parameters as well as returns.

All notable changes to this project will be documented in this file.

Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ any>`). Class fields with explicit annotations report one property finding,
including public, private, protected, static, readonly, declare, and optional
fields. Interface declarations and direct object type aliases report their
properties, method parameters and returns, and index signatures individually.
Function type parameters and returns nested in another annotation contribute to
that enclosing finding. When one annotation contains both, `any` takes
precedence over `unknown`.
Function and constructor signature parameters and returns nested in another
annotation contribute to that enclosing finding. When one annotation contains
both, `any` takes precedence over `unknown`.

## Output

Expand Down Expand Up @@ -170,9 +170,9 @@ variables and class fields (for example, `const x = 5` or `value = 5`) are not
flagged — only explicit annotation sites are audited.

Nested `any` and `unknown` are propagated through supported TypeScript type
annotations, including type predicates and mapped-type key constraints,
remapped keys, and values. When both occur in one annotation, `any` takes
precedence.
annotations, including function and constructor signatures, type predicates,
and mapped-type key constraints, remapped keys, and values. When both occur in
one annotation, `any` takes precedence.

## Contributing

Expand Down
20 changes: 20 additions & 0 deletions src/parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,26 @@ describe('classifyTypeAnnotation for nested weak types', () => {
expect(nodes.find(node => node.kind === 'var')?.status).toBe(expected);
});

it.each([
['any parameter', 'new (value: any) => Widget', AnnotationStatus.any],
['unknown parameter', 'new (value: unknown) => Widget', AnnotationStatus.unknown],
['any return', 'new (value: string) => any', AnnotationStatus.any],
['unknown return', 'new (value: string) => unknown', AnnotationStatus.unknown],
['fully typed constructor', 'new (value: string) => Widget', AnnotationStatus.explicit],
])('classifies a constructor type with an %s', (_name, annotation, expected) => {
const nodes = parseSource(`const Factory: ${annotation} = null as never;`);
expect(nodes.find(node => node.kind === 'var')?.status).toBe(expected);
});

it.each([
'new (value: unknown) => any',
'new (value: any) => unknown',
'new (first: unknown, second: any) => Widget',
])('gives any deterministic precedence within constructor type %s', annotation => {
const nodes = parseSource(`const Factory: ${annotation} = null as never;`);
expect(nodes.find(node => node.kind === 'var')?.status).toBe(AnnotationStatus.any);
});

it.each([
'{ first: unknown; second: any }',
'{ first: any; second: unknown }',
Expand Down
3 changes: 1 addition & 2 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,7 @@ export function classifyTypeAnnotation(typeNode: TSESTree.TypeNode): AnnotationS
// TSConstructorType
if (typeNode.type === 'TSConstructorType') {
const ct = typeNode as TSESTree.TSConstructorType;
if (ct.returnType) return classifyTypeAnnotation(ct.returnType.typeAnnotation);
return AnnotationStatus.explicit;
return classifyFunctionTypeParts(ct.params, ct.returnType);
}

// TSTypePredicate — check the asserted type (`value is T` / `asserts value is T`)
Expand Down
Loading