feat: oxlint type checked rules

This commit is contained in:
Julian Sommer
2026-03-24 10:14:31 +10:00
parent 35d0df5b56
commit 3467e0cf22
10 changed files with 36 additions and 18 deletions
@@ -10,6 +10,10 @@
"@tanstack/eslint-plugin-query",
"@tanstack/eslint-plugin-router"
],
"options": {
"typeAware": true,
"typeCheck": true
},
"rules": {
"@tanstack/router/create-route-property-order": "warn",
"@tanstack/router/route-param-names": "error",
@@ -30,10 +34,18 @@
"eslint/sort-vars": "off",
"import/consistent-type-specifier-style": "off",
"import/first": "off",
"promise/prefer-await-to-callbacks": "off",
"react/jsx-handler-names": "off",
"react/no-unescaped-entities": "off",
"promise/prefer-await-to-callbacks": "off",
"react-perf/jsx-no-new-function-as-prop": "off",
"typescript/no-confusing-void-expression": "off",
"typescript/prefer-nullish-coalescing": "off",
"typescript/return-await": "off",
"typescript/no-floating-promises": "off",
"typescript/strict-boolean-expressions": "off",
"typescript/no-misused-promises": "off",
"typescript/only-throw-error": "off",
"typescript/promise-function-async": "off",
"unicorn/filename-case": [
"error",
{ "cases": { "kebabCase": true, "camelCase": true } }
@@ -47,6 +59,10 @@
],
"rules": {
"typescript/consistent-type-imports": "off",
"typescript/no-unsafe-argument": "off",
"typescript/no-unsafe-assignment": "off",
"typescript/no-unsafe-member-access": "off",
"typescript/no-unsafe-type-assertion": "off",
"unicorn/no-useless-undefined": "off"
}
}
@@ -4,10 +4,10 @@
"type": "module",
"scripts": {
"dev": "vite --port 3000",
"build": "vite build && tsgo",
"build": "vite build",
"preview": "vite preview",
"check": "oxlint; oxfmt --check",
"fix": "oxlint --fix; oxfmt",
"check": "oxlint src; oxfmt --check",
"fix": "oxlint --fix src; oxfmt",
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"test:watch": "vitest"
@@ -56,7 +56,7 @@ export function InputGroupAddon({
data-align={align}
data-slot="input-group-addon"
onClick={(e) => {
if ((e.target as HTMLElement).closest("button")) {
if (e.target instanceof HTMLElement && e.target.closest("button")) {
return
}
e.currentTarget.parentElement?.querySelector("input")?.focus()
@@ -180,6 +180,10 @@ export function Sidebar({
}
if (isMobile) {
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
const mobileStyle = {
"--sidebar-width": SIDEBAR_WIDTH_MOBILE,
} as React.CSSProperties
return (
<Sheet onOpenChange={setOpenMobile} open={openMobile} {...props}>
<SheetContent
@@ -188,11 +192,7 @@ export function Sidebar({
data-sidebar="sidebar"
data-slot="sidebar"
side={side}
style={
{
"--sidebar-width": SIDEBAR_WIDTH_MOBILE,
} as React.CSSProperties
}
style={mobileStyle}
>
<SheetHeader className="sr-only">
<SheetTitle>Sidebar</SheetTitle>
@@ -654,11 +654,8 @@ export function SidebarMenuSkeleton({
<Skeleton
className="h-4 max-w-(--skeleton-width) flex-1"
data-sidebar="menu-skeleton-text"
style={
{
"--skeleton-width": width,
} as React.CSSProperties
}
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
style={{ "--skeleton-width": width } as React.CSSProperties}
/>
</div>
)
@@ -29,6 +29,7 @@ describe("useCopyToClipboard", () => {
await result.current.copy("hello")
})
// oxlint-disable-next-line typescript/unbound-method -- vitest mock
expect(navigator.clipboard.writeText).toHaveBeenCalledWith("hello")
expect(result.current.copied).toBe(true)
})
@@ -27,7 +27,7 @@ export function getCredentials(): AwsCredentials | null {
credentialsCache = null
return null
}
const parsed = JSON.parse(stored)
const parsed: unknown = JSON.parse(stored)
const result = awsCredentialsSchema.safeParse(parsed)
credentialsCache = result.success ? result.data : null
return credentialsCache
@@ -71,6 +71,7 @@ export function getS3Client(): S3Client {
applyToStack: (stack) => {
stack.add(
(next) => (args) => {
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- smithy middleware args.request is typed as unknown
const request = (args as { request?: { path?: string } }).request
if (request?.path?.endsWith("/") && request.path !== "/") {
request.path = request.path.slice(0, -1)
@@ -112,6 +112,7 @@ export function useCreateInstance() {
mutationFn: (params: CreateInstanceParams) => {
const command = new RunInstancesCommand({
ImageId: params.imageId,
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- AWS SDK expects _InstanceType enum
InstanceType: params.instanceType as _InstanceType,
KeyName: params.keyName,
MinCount: params.count,
@@ -34,8 +34,10 @@ export function ObjectListItem({
const response = await getS3Client().send(command)
if (response.Body) {
// oxlint-disable-next-line typescript/no-unsafe-call, typescript/no-unsafe-member-access, typescript/no-unsafe-assignment
const blob = await response.Body.transformToByteArray()
const url = URL.createObjectURL(new Blob([blob]))
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
const url = URL.createObjectURL(new Blob([blob as BlobPart]))
const link = document.createElement("a")
link.href = url
@@ -68,7 +68,7 @@ function BucketObjectsWithPrefix() {
return (
<>
{/* oxlint-disable-next-line typescript/no-explicit-any valid }*/}
{/* oxlint-disable-next-line typescript/no-explicit-any, typescript/no-unsafe-type-assertion, typescript/no-unsafe-assignment -- dynamic route path */}
<BackLink to={parentPath as any}>Back</BackLink>
<div className="mb-6">
<div className="mb-2 flex items-center justify-between">