-
-
Notifications
You must be signed in to change notification settings - Fork 202
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
27 changed files
with
605 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
--- | ||
title: Type & Interface Members | ||
sidebar: | ||
label: Type Members | ||
order: 6 | ||
badge: | ||
text: Experimental | ||
variant: caution | ||
--- | ||
|
||
:::caution[Warning] | ||
|
||
This is a highly experimental feature. Currently: | ||
|
||
- There will be false positives. | ||
- Only members of **exported** types and interfaces are considered | ||
- Only members of **selected** types and interfaces are considered (see examples | ||
below) | ||
|
||
::: | ||
|
||
## Usage | ||
|
||
Reporting unused type and interface members is disabled by default. To enable | ||
this, make sure to include the `typeMembers` issue type: | ||
|
||
```sh | ||
knip --include typeMembers | ||
``` | ||
|
||
Below are code examples to get an idea of what Knip should catch. Also see the | ||
fixture folders ([1][1] & [2][2]) for slightly more involved examples. | ||
|
||
## Interface Members | ||
|
||
In the next example, `Dog.wings` is reported as unused: | ||
|
||
```ts | ||
interface Dog { | ||
legs: number; | ||
wings: boolean; | ||
} | ||
|
||
const charlie: Dog = { | ||
legs: 4, | ||
}; | ||
``` | ||
|
||
## Type Members | ||
|
||
In the next example, `Pet.fins` and `Cat.horn` are reported as unused: | ||
|
||
```ts | ||
type Pet = { | ||
legs: number; | ||
fins: boolean; | ||
}; | ||
|
||
type Cat = { | ||
legs: Pet['legs']; | ||
horn: boolean; | ||
}; | ||
|
||
const coco: Cat = { | ||
legs: 4, | ||
}; | ||
``` | ||
|
||
## Function Arguments | ||
|
||
In the next example, `Args.caseB` is reported as unused: | ||
|
||
```ts | ||
export interface Args { | ||
caseA: boolean; | ||
caseB: boolean; | ||
} | ||
|
||
function fn(options: Args) { | ||
if (options.caseA) return 1; | ||
} | ||
|
||
fn({ caseA: true }); | ||
``` | ||
|
||
## JSX Component Props | ||
|
||
Component props that are not referenced, are reported as unused. | ||
|
||
Note that props that are referenced inside the component, but never passed in as | ||
part of the JSX props or argument(s), are not reported. | ||
|
||
### Example 1: Passed prop | ||
|
||
In the next example `unusedProp` is reported as unused: | ||
|
||
```tsx | ||
export interface ComponentProps { | ||
usedProp: boolean; | ||
unusedProp: boolean; | ||
} | ||
|
||
const Component: React.FC<ComponentProps> = props => null; | ||
|
||
const App = () => ( | ||
<> | ||
<Component usedProp={true} />; | ||
<Component {...{ usedProp: true }} /> | ||
{ React.createElement(Component, { usedProp: true }); } | ||
</> | ||
); | ||
``` | ||
|
||
### Example 2: Used prop | ||
|
||
In the next example `deep.unusedProp` is reported as unused: | ||
|
||
```tsx | ||
export type ComponentProps = { | ||
usedProp: boolean; | ||
deep: { | ||
unusedProp: boolean; | ||
}; | ||
}; | ||
|
||
const Component: React.FC<ComponentProps> = props => ( | ||
<span>{props.usedProp}</span> | ||
); | ||
|
||
const App = () => <Component />; | ||
``` | ||
|
||
## Closing Notes | ||
|
||
- Only members of **exported** interfaces and types are considered. | ||
- Knip tries to consider only **relevant** interfaces and types. | ||
- Don't start exporting or reusing interfaces and types for the sake of Knip | ||
detecting unused properties. | ||
|
||
[1]: | ||
https://github.com/webpro-nl/knip/tree/feat/unused-exported-type-members/packages/knip/fixtures/type-members | ||
[2]: | ||
https://github.com/webpro-nl/knip/tree/feat/unused-exported-type-members/packages/knip/fixtures/type-members2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { MyInterface, ExtendedInterface } from './interfaces'; | ||
import { MyType, WithIntersection, WithUnion } from './types'; | ||
import type { PropsA, PropsB, PropsC, PropsD, FnArg } from './props'; | ||
import type { OnlyTypedUsage } from './interfaces'; | ||
|
||
const interfaceRef: MyInterface = { | ||
usedInterfaceMember: true, | ||
}; | ||
|
||
type TypeRef = { | ||
prop: MyType['usedTypeMember']; | ||
key: MyInterface['usedKey']; | ||
}; | ||
|
||
class ImplementsUsage implements Pick<MyInterface, 'usedInImplements' | 'usedInImplementsInternal'> { | ||
usedInImplements = true; | ||
} | ||
|
||
const interfaceUsage: ExtendedInterface = { | ||
usedInExtends: true, | ||
}; | ||
|
||
const intersectionUsage: WithIntersection = { | ||
usedInIntersection: true, | ||
}; | ||
|
||
const unionUsage: WithUnion = { | ||
usedInUnion: true, | ||
}; | ||
|
||
interfaceRef; | ||
ImplementsUsage; | ||
interfaceUsage; | ||
intersectionUsage; | ||
unionUsage; | ||
|
||
declare const React: any; | ||
|
||
declare namespace React { | ||
type FC<P = Record<string, unknown>> = (props: P) => any; | ||
} | ||
|
||
const ComponentA: React.FC<PropsA> = () => null; | ||
|
||
const ComponentB: React.FC<PropsB> = props => <div {...props} />; | ||
|
||
const ComponentC: React.FC<PropsC> = props => <div>{props.usedPropC}</div>; | ||
|
||
const ComponentD: React.FC<PropsD> = props => <div>{props.usedPropC}</div>; | ||
|
||
const App = () => ( | ||
<> | ||
<ComponentA usedProp1={true} /> | ||
<ComponentA usedProp2={true} /> | ||
<ComponentB {...{ usedPropB: true }} /> | ||
<ComponentC /> | ||
{React.createElement(ComponentD, { usedPropD: true })} | ||
</> | ||
); | ||
|
||
function fn(options: FnArg) { | ||
if (options.optionA) return 1; | ||
// if (options.optionB) return 2; | ||
} | ||
|
||
fn({ optionA: true }); | ||
|
||
type TypedDocumentNode<T> = T extends string ? () => string : () => number; | ||
|
||
export const anotherFn = async (): Promise<() => number> => { | ||
const info = await f({ | ||
query: (() => 1) as TypedDocumentNode<OnlyTypedUsage>, | ||
}); | ||
return info; | ||
}; | ||
|
||
export const getQuery: TypedDocumentNode<OnlyTypedUsage> = () => 1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
export interface MyInterface { | ||
usedInterfaceMember?: boolean; | ||
usedKey?: boolean; | ||
usedInExtends?: boolean; | ||
usedInImplements?: boolean; | ||
|
||
usedInExtendsInternal?: boolean; | ||
usedInImplementsInternal?: boolean; | ||
|
||
unusedInterfaceMember?: boolean; | ||
'unused-interface-quoted'?: boolean; | ||
} | ||
|
||
export interface ExtendedInterface extends Pick<MyInterface, 'usedInExtends' | 'usedInExtendsInternal'> { | ||
boolA?: true; | ||
} | ||
|
||
class ImplementingClass implements Exclude<MyInterface, 'usedInExtends' | 'usedInExtendsInternal'> { | ||
usedInImplementsInternal = true; | ||
} | ||
|
||
const internalInterfaceUsage: ExtendedInterface = { | ||
usedInExtendsInternal: true, | ||
}; | ||
|
||
ImplementingClass; | ||
internalInterfaceUsage; | ||
|
||
export interface OnlyTypedUsage { | ||
id: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"name": "@fixtures/type-members", | ||
"knip": { | ||
"include": ["typeMembers"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
export interface PropsA { | ||
usedProp1?: boolean; | ||
usedProp2?: boolean; | ||
unusedPropA?: boolean; | ||
} | ||
|
||
export type PropsB = { | ||
usedPropB: boolean; | ||
unusedPropB?: boolean; | ||
}; | ||
|
||
export type PropsC = { | ||
usedPropC?: boolean; | ||
unusedPropC?: boolean; | ||
}; | ||
|
||
export type PropsD = { | ||
usedPropC?: boolean; | ||
unusedPropD?: boolean; | ||
}; | ||
|
||
export interface FnArg { | ||
optionA?: boolean; | ||
optionB?: boolean; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
export type MyType = { | ||
usedTypeMember?: boolean; | ||
usedInUnion?: boolean; | ||
usedInIntersection?: boolean; | ||
|
||
usedInIntersectionInternal?: boolean; | ||
usedInUnionInternal?: boolean; | ||
|
||
unusedTypeMember?: boolean; | ||
'unused-type-quoted'?: boolean; | ||
}; | ||
|
||
export type WithIntersection = { boolB?: boolean } & Omit<MyType, 'usedInExtends' | 'usedInExtendsInternal'>; | ||
export type WithUnion = { boolC?: boolean } | Omit<MyType, 'usedInExtends' | 'usedInExtendsInternal'>; | ||
|
||
const internalIntersectionUsage: WithIntersection = { | ||
usedInIntersectionInternal: true, | ||
}; | ||
|
||
const internalUnionUsage: WithUnion = { | ||
usedInUnionInternal: true, | ||
}; | ||
|
||
internalIntersectionUsage; | ||
internalUnionUsage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { MyInterface } from './interfaces'; | ||
import { MyType } from './types'; | ||
|
||
// interface ExtendedInterface<T extends MyInterface> { | ||
// get: <K extends keyof T['keyA']>(key: K) => T['keyA'][K] | undefined; | ||
// } | ||
|
||
const i: MyInterface = { | ||
keyA: '', | ||
keyB: { | ||
subB: '', | ||
}, | ||
}; | ||
|
||
const t: MyType = { | ||
keyA: '', | ||
keyB: { | ||
subB: '', | ||
}, | ||
}; | ||
|
||
i; | ||
t; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export interface MyInterface { | ||
keyA: string; | ||
keyB: { | ||
subA: string; | ||
subB: string; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"name": "@fixtures/type-members2", | ||
"knip": { | ||
"include": ["typeMembers"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"compilerOptions": {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export type MyType = { | ||
keyA: string; | ||
keyB: { | ||
subA: string; | ||
subB: string; | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.