fix: type compatibility with exactOptionalPropertyTypes (#5236)

Co-authored-by: Alex Yang <himself65@outlook.com>
This commit is contained in:
KinfeMichael Tariku
2025-10-13 21:36:38 +00:00
committed by GitHub
co-authored by Alex Yang
parent 5c878f5c83
commit f27231cf8d
15 changed files with 175 additions and 109 deletions
@@ -0,0 +1,12 @@
{
"name": "tsconfig-exact-optional-property-types",
"private": true,
"type": "module",
"scripts": {
"typecheck": "tsc --project tsconfig.json"
},
"dependencies": {
"better-auth": "workspace:*",
"better-sqlite3": "^12.4.1"
}
}
@@ -0,0 +1,28 @@
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";
import { nextCookies } from "better-auth/next-js";
import Database from "better-sqlite3";
import { createAuthClient } from "better-auth/react";
import {
inferAdditionalFields,
organizationClient,
} from "better-auth/client/plugins";
const auth = betterAuth({
database: new Database("./sqlite.db"),
trustedOrigins: [],
emailAndPassword: {
enabled: true,
},
plugins: [organization(), nextCookies()],
user: {
additionalFields: {},
},
});
const authClient = createAuthClient({
baseURL: "http://localhost:3000",
plugins: [inferAdditionalFields<typeof auth>(), organizationClient()],
});
authClient.useActiveOrganization();
authClient.useSession();
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "NodeNext",
"outDir": "dist",
"strict": true,
"exactOptionalPropertyTypes": true,
"skipLibCheck": true,
"types": ["node"],
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx",
"moduleResolution": "node16"
}
}
@@ -11,8 +11,7 @@ import type {
} from "@better-auth/core/middleware";
import { createDefu } from "defu";
import { shouldPublishLog } from "@better-auth/core/env";
import type { AuthContext } from "@better-auth/core";
import type { HookEndpointContext } from "../types";
import type { AuthContext, HookEndpointContext } from "@better-auth/core";
type InternalContext = InputContext<string, any> &
EndpointContext<string, any> & {
+17 -14
View File
@@ -27,22 +27,25 @@ export function capitalizeFirstLetter(str: string) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
type InferResolvedHooks<O extends BetterAuthClientOptions> =
O["plugins"] extends Array<infer Plugin>
? Plugin extends BetterAuthClientPlugin
? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
? Atoms extends Record<string, any>
? {
[key in keyof Atoms as IsSignal<key> extends true
? never
: key extends string
? `use${Capitalize<key>}`
: never]: () => ReturnType<Atoms[key]["get"]>;
}
type InferResolvedHooks<O extends BetterAuthClientOptions> = O extends {
plugins: Array<infer Plugin>;
}
? UnionToIntersection<
Plugin extends BetterAuthClientPlugin
? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
? Atoms extends Record<string, any>
? {
[key in keyof Atoms as IsSignal<key> extends true
? never
: key extends string
? `use${Capitalize<key>}`
: never]: () => ReturnType<Atoms[key]["get"]>;
}
: {}
: {}
: {}
: {}
: {};
>
: {};
export function createAuthClient<Option extends BetterAuthClientOptions>(
options?: Option,
+17 -14
View File
@@ -27,22 +27,25 @@ export function capitalizeFirstLetter(str: string) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
type InferResolvedHooks<O extends BetterAuthClientOptions> =
O["plugins"] extends Array<infer Plugin>
? Plugin extends BetterAuthClientPlugin
? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
? Atoms extends Record<string, any>
? {
[key in keyof Atoms as IsSignal<key> extends true
? never
: key extends string
? `use${Capitalize<key>}`
: never]: () => ReturnType<Atoms[key]["get"]>;
}
type InferResolvedHooks<O extends BetterAuthClientOptions> = O extends {
plugins: Array<infer Plugin>;
}
? UnionToIntersection<
Plugin extends BetterAuthClientPlugin
? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
? Atoms extends Record<string, any>
? {
[key in keyof Atoms as IsSignal<key> extends true
? never
: key extends string
? `use${Capitalize<key>}`
: never]: () => ReturnType<Atoms[key]["get"]>;
}
: {}
: {}
: {}
: {}
: {};
>
: {};
export function createAuthClient<Option extends BetterAuthClientOptions>(
options?: Option,
+17 -14
View File
@@ -25,22 +25,25 @@ function getAtomKey(str: string) {
return `use${capitalizeFirstLetter(str)}`;
}
type InferResolvedHooks<O extends BetterAuthClientOptions> =
O["plugins"] extends Array<infer Plugin>
? Plugin extends BetterAuthClientPlugin
? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
? Atoms extends Record<string, any>
? {
[key in keyof Atoms as IsSignal<key> extends true
? never
: key extends string
? `use${Capitalize<key>}`
: never]: () => Accessor<ReturnType<Atoms[key]["get"]>>;
}
type InferResolvedHooks<O extends BetterAuthClientOptions> = O extends {
plugins: Array<infer Plugin>;
}
? UnionToIntersection<
Plugin extends BetterAuthClientPlugin
? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
? Atoms extends Record<string, any>
? {
[key in keyof Atoms as IsSignal<key> extends true
? never
: key extends string
? `use${Capitalize<key>}`
: never]: () => Accessor<ReturnType<Atoms[key]["get"]>>;
}
: {}
: {}
: {}
: {}
: {};
>
: {};
export function createAuthClient<Option extends BetterAuthClientOptions>(
options?: Option,
+17 -14
View File
@@ -19,22 +19,25 @@ import type {
} from "@better-fetch/fetch";
import type { BASE_ERROR_CODES } from "@better-auth/core/error";
type InferResolvedHooks<O extends BetterAuthClientOptions> =
O["plugins"] extends Array<infer Plugin>
? Plugin extends BetterAuthClientPlugin
? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
? Atoms extends Record<string, any>
? {
[key in keyof Atoms as IsSignal<key> extends true
? never
: key extends string
? `use${Capitalize<key>}`
: never]: () => Atoms[key];
}
type InferResolvedHooks<O extends BetterAuthClientOptions> = O extends {
plugins: Array<infer Plugin>;
}
? UnionToIntersection<
Plugin extends BetterAuthClientPlugin
? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
? Atoms extends Record<string, any>
? {
[key in keyof Atoms as IsSignal<key> extends true
? never
: key extends string
? `use${Capitalize<key>}`
: never]: () => Atoms[key];
}
: {}
: {}
: {}
: {}
: {};
>
: {};
export function createAuthClient<Option extends BetterAuthClientOptions>(
options?: Option,
+17 -14
View File
@@ -19,22 +19,25 @@ import type {
} from "@better-fetch/fetch";
import type { BASE_ERROR_CODES } from "@better-auth/core/error";
type InferResolvedHooks<O extends BetterAuthClientOptions> =
O["plugins"] extends Array<infer Plugin>
? Plugin extends BetterAuthClientPlugin
? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
? Atoms extends Record<string, any>
? {
[key in keyof Atoms as IsSignal<key> extends true
? never
: key extends string
? `use${Capitalize<key>}`
: never]: Atoms[key];
}
type InferResolvedHooks<O extends BetterAuthClientOptions> = O extends {
plugins: Array<infer Plugin>;
}
? UnionToIntersection<
Plugin extends BetterAuthClientPlugin
? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
? Atoms extends Record<string, any>
? {
[key in keyof Atoms as IsSignal<key> extends true
? never
: key extends string
? `use${Capitalize<key>}`
: never]: Atoms[key];
}
: {}
: {}
: {}
: {}
: {};
>
: {};
export function createAuthClient<Option extends BetterAuthClientOptions>(
options?: Option,
+19 -16
View File
@@ -24,24 +24,27 @@ function getAtomKey(str: string) {
return `use${capitalizeFirstLetter(str)}`;
}
type InferResolvedHooks<O extends BetterAuthClientOptions> =
O["plugins"] extends Array<infer Plugin>
? Plugin extends BetterAuthClientPlugin
? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
? Atoms extends Record<string, any>
? {
[key in keyof Atoms as IsSignal<key> extends true
? never
: key extends string
? `use${Capitalize<key>}`
: never]: () => DeepReadonly<
Ref<ReturnType<Atoms[key]["get"]>>
>;
}
type InferResolvedHooks<O extends BetterAuthClientOptions> = O extends {
plugins: Array<infer Plugin>;
}
? UnionToIntersection<
Plugin extends BetterAuthClientPlugin
? Plugin["getAtoms"] extends (fetch: any) => infer Atoms
? Atoms extends Record<string, any>
? {
[key in keyof Atoms as IsSignal<key> extends true
? never
: key extends string
? `use${Capitalize<key>}`
: never]: () => DeepReadonly<
Ref<ReturnType<Atoms[key]["get"]>>
>;
}
: {}
: {}
: {}
: {}
: {};
>
: {};
export function createAuthClient<Option extends BetterAuthClientOptions>(
options?: Option,
-11
View File
@@ -1,11 +0,0 @@
import type { EndpointContext, InputContext } from "better-call";
import type { AuthContext } from "@better-auth/core";
export type HookEndpointContext = EndpointContext<string, any> &
Omit<InputContext<string, any>, "method"> & {
context: AuthContext & {
returned?: unknown;
responseHeaders?: Headers;
};
headers?: Headers;
};
-1
View File
@@ -8,7 +8,6 @@ export type {
export type * from "./models";
export type * from "../init";
export type * from "./plugins";
export type * from "./context";
export type * from "./adapter";
export * from "../client/types";
export * from "./api";
+1 -1
View File
@@ -11,7 +11,7 @@ export type {
GenericEndpointContext,
InternalAdapter,
} from "./context";
export type { BetterAuthPlugin } from "./plugin";
export type { BetterAuthPlugin, HookEndpointContext } from "./plugin";
export type {
BetterAuthClientPlugin,
BetterAuthClientOptions,
+2 -2
View File
@@ -18,13 +18,13 @@ type DeepPartial<T> = T extends Function
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
type HookEndpointContext = EndpointContext<string, any> &
export type HookEndpointContext = EndpointContext<string, any> &
Omit<InputContext<string, any>, "method"> & {
context: AuthContext & {
returned?: unknown;
responseHeaders?: Headers;
};
headers?: Headers;
headers?: Headers | undefined;
};
export type BetterAuthPlugin = {
+13 -6
View File
@@ -834,6 +834,15 @@ importers:
specifier: 4.33.2
version: 4.33.2(@cloudflare/workers-types@4.20250903.0)
e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types:
dependencies:
better-auth:
specifier: workspace:*
version: link:../../../../../packages/better-auth
better-sqlite3:
specifier: ^12.4.1
version: 12.4.1
e2e/smoke/test/fixtures/tsconfig-verbatim-module-syntax-node10:
dependencies:
'@better-auth/expo':
@@ -15269,7 +15278,7 @@ snapshots:
postcss: 8.4.49
resolve-from: 5.0.0
optionalDependencies:
expo: 54.0.10(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.8)(graphql@16.11.0)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.2))(@types/react@19.2.2)(react@19.2.0))(react@19.2.0)
expo: 54.0.10(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.8)(graphql@16.11.0)(react-native@0.81.4(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.2))(@react-native/metro-config@0.81.0(@babel/core@7.28.4))(@types/react@19.2.2)(react@19.2.0))(react@19.2.0)
transitivePeerDependencies:
- bufferutil
- supports-color
@@ -15354,7 +15363,7 @@ snapshots:
'@expo/json-file': 10.0.7
'@react-native/normalize-colors': 0.81.4
debug: 4.4.3
expo: 54.0.10(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.8)(graphql@16.11.0)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.2))(@types/react@19.2.2)(react@19.2.0))(react@19.2.0)
expo: 54.0.10(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.8)(graphql@16.11.0)(react-native@0.81.4(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.2))(@react-native/metro-config@0.81.0(@babel/core@7.28.4))(@types/react@19.2.2)(react@19.2.0))(react@19.2.0)
resolve-from: 5.0.0
semver: 7.7.2
xml2js: 0.6.0
@@ -17684,9 +17693,7 @@ snapshots:
metro-runtime: 0.83.3
transitivePeerDependencies:
- '@babel/core'
- bufferutil
- supports-color
- utf-8-validate
optional: true
'@react-native/normalize-colors@0.74.89': {}
@@ -19666,7 +19673,7 @@ snapshots:
resolve-from: 5.0.0
optionalDependencies:
'@babel/runtime': 7.28.4
expo: 54.0.10(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.8)(graphql@16.11.0)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.2))(@types/react@19.2.2)(react@19.2.0))(react@19.2.0)
expo: 54.0.10(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.8)(graphql@16.11.0)(react-native@0.81.4(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.2))(@react-native/metro-config@0.81.0(@babel/core@7.28.4))(@types/react@19.2.2)(react@19.2.0))(react@19.2.0)
transitivePeerDependencies:
- '@babel/core'
- supports-color
@@ -21150,7 +21157,7 @@ snapshots:
expo-keep-awake@15.0.7(expo@54.0.10)(react@19.2.0):
dependencies:
expo: 54.0.10(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.8)(graphql@16.11.0)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.2))(@types/react@19.2.2)(react@19.2.0))(react@19.2.0)
expo: 54.0.10(@babel/core@7.28.4)(@expo/metro-runtime@6.1.2)(expo-router@6.0.8)(graphql@16.11.0)(react-native@0.81.4(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.2))(@react-native/metro-config@0.81.0(@babel/core@7.28.4))(@types/react@19.2.2)(react@19.2.0))(react@19.2.0)
react: 19.2.0
expo-linking@7.1.7(expo@54.0.10)(react-native@0.80.2(@babel/core@7.28.4)(@react-native-community/cli@20.0.1(typescript@5.9.2))(@types/react@19.2.2)(react@19.2.0))(react@19.2.0):