Skip to content

Commit

Permalink
Type cleanup (#78)
Browse files Browse the repository at this point in the history
Co-authored-by: Julius Marminge <julius0216@outlook.com>
  • Loading branch information
chungweileong94 and juliusmarminge committed Jun 12, 2023
1 parent e4d8eee commit 245f6ad
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 91 deletions.
5 changes: 5 additions & 0 deletions .changeset/wet-crabs-tease.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@t3-oss/env-core": patch
---

Cleanup types
98 changes: 47 additions & 51 deletions packages/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ export type Simplify<T> = {
// eslint-disable-next-line @typescript-eslint/ban-types
} & {};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Impossible<T extends Record<string, any>> = Partial<
Record<keyof T, never>
>;

export interface BaseOptions {
/**
* How to determine whether the app is running on the server or the client.
Expand All @@ -32,6 +37,40 @@ export interface BaseOptions {
skipValidation?: boolean;
}

export interface LooseOptions extends BaseOptions {
runtimeEnvStrict?: never;
/**
* Runtime Environment variables to use for validation - `process.env`, `import.meta.env` or similar.
* Unlike `runtimeEnvStrict`, this doesn't enforce that all environment variables are set.
*/
runtimeEnv: Record<string, string | boolean | number | undefined>;
}

export interface StrictOptions<
TPrefix extends string,
TServer extends Record<string, ZodType>,
TClient extends Record<string, ZodType>
> extends BaseOptions {
/**
* Runtime Environment variables to use for validation - `process.env`, `import.meta.env` or similar.
* Enforces all environment variables to be set. Required in for example Next.js Edge and Client runtimes.
*/
runtimeEnvStrict: Record<
| {
[TKey in keyof TClient]: TKey extends `${TPrefix}${string}`
? TKey
: never;
}[keyof TClient]
| {
[TKey in keyof TServer]: TKey extends `${TPrefix}${string}`
? never
: TKey;
}[keyof TServer],
string | boolean | number | undefined
>;
runtimeEnv?: never;
}

export interface ClientOptions<
TPrefix extends string,
TClient extends Record<string, ZodType>
Expand All @@ -45,18 +84,13 @@ export interface ClientOptions<
* Specify your client-side environment variables schema here. This way you can ensure the app isn't
* built with invalid env vars. To expose them to the client, prefix them with `NEXT_PUBLIC_`.
*/
client: {
client: Partial<{
[TKey in keyof TClient]: TKey extends `${TPrefix}${string}`
? TClient[TKey]
: ErrorMessage<`${TKey extends string
? TKey
: never} is not prefixed with ${TPrefix}.`>;
};
}

export interface WithoutClientOptions {
clientPrefix?: never;
client?: never;
}>;
}

export interface ServerOptions<
Expand All @@ -67,53 +101,15 @@ export interface ServerOptions<
* Specify your server-side environment variables schema here. This way you can ensure the app isn't
* built with invalid env vars.
*/
server: {
server: Partial<{
[TKey in keyof TServer]: TPrefix extends ""
? TServer[TKey]
: TKey extends `${TPrefix}${string}`
? ErrorMessage<`${TKey extends `${TPrefix}${string}`
? TKey
: never} should not prefixed with ${TPrefix}.`>
: TServer[TKey];
};
}

export interface WithoutServerOptions {
server?: never;
}

export interface LooseOptions extends BaseOptions {
runtimeEnvStrict?: never;
/**
* Runtime Environment variables to use for validation - `process.env`, `import.meta.env` or similar.
* Unlike `runtimeEnvStrict`, this doesn't enforce that all environment variables are set.
*/
runtimeEnv: Record<string, string | boolean | number | undefined>;
}

export interface StrictOptions<
TPrefix extends string,
TServer extends Record<string, ZodType>,
TClient extends Record<string, ZodType>
> extends BaseOptions {
/**
* Runtime Environment variables to use for validation - `process.env`, `import.meta.env` or similar.
* Enforces all environment variables to be set. Required in for example Next.js Edge and Client runtimes.
*/
runtimeEnvStrict: Record<
| {
[TKey in keyof TClient]: TKey extends `${TPrefix}${string}`
? TKey
: never;
}[keyof TClient]
| {
[TKey in keyof TServer]: TKey extends `${TPrefix}${string}`
? never
: TKey;
}[keyof TServer],
string | boolean | number | undefined
>;
runtimeEnv?: never;
}>;
}

export type ServerClientOptions<
Expand All @@ -122,10 +118,10 @@ export type ServerClientOptions<
TClient extends Record<string, ZodType>
> =
| (ClientOptions<TPrefix, TClient> & ServerOptions<TPrefix, TServer>)
| (WithoutClientOptions & ServerOptions<TPrefix, TServer>)
| (ClientOptions<TPrefix, TClient> & WithoutServerOptions);
| (ServerOptions<TPrefix, TServer> & Impossible<ClientOptions<never, never>>)
| (ClientOptions<TPrefix, TClient> & Impossible<ServerOptions<never, never>>);

export type createEnvParams<
export type EnvOptions<
TPrefix extends string,
TServer extends Record<string, ZodType>,
TClient extends Record<string, ZodType>
Expand All @@ -139,7 +135,7 @@ export function createEnv<
TServer extends Record<string, ZodType> = NonNullable<unknown>,
TClient extends Record<string, ZodType> = NonNullable<unknown>
>(
opts: createEnvParams<TPrefix, TServer, TClient>
opts: EnvOptions<TPrefix, TServer, TClient>
): Simplify<z.infer<ZodObject<TServer>> & z.infer<ZodObject<TClient>>> {
const runtimeEnv = opts.runtimeEnvStrict ?? opts.runtimeEnv ?? process.env;

Expand Down
22 changes: 2 additions & 20 deletions packages/nextjs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,8 @@ export function createEnv<
ZodType
> = NonNullable<unknown>
>({ runtimeEnv, ...opts }: Options<TServer, TClient>) {
const client =
typeof opts.client === "object"
? opts.client
: ({} as {
[TKey in keyof TClient]: TKey extends `NEXT_PUBLIC_${string}`
? TClient[TKey]
: `${TKey extends string
? TKey
: never} is not prefixed with NEXT_PUBLIC_.`;
});
const server =
typeof opts.server === "object"
? opts.server
: ({} as {
[TKey in keyof TServer]: TKey extends `NEXT_PUBLIC_${string}`
? `${TKey extends `NEXT_PUBLIC_${string}`
? TKey
: never} should not prefixed with NEXT_PUBLIC_.`
: TServer[TKey];
});
const client = typeof opts.client === "object" ? opts.client : {};
const server = typeof opts.server === "object" ? opts.server : {};

return createEnvCore<ClientPrefix, TServer, TClient>({
...opts,
Expand Down
22 changes: 2 additions & 20 deletions packages/nuxt/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,8 @@ export function createEnv<
TServer extends Record<string, ZodType> = NonNullable<unknown>,
TClient extends Record<string, ZodType> = NonNullable<unknown>
>(opts: Options<TServer, TClient>) {
const client =
typeof opts.client === "object"
? opts.client
: ({} as {
[TKey in keyof TClient]: TKey extends `NUXT_PUBLIC_${string}`
? TClient[TKey]
: `${TKey extends string
? TKey
: never} is not prefixed with NUXT_PUBLIC_.`;
});
const server =
typeof opts.server === "object"
? opts.server
: ({} as {
[TKey in keyof TServer]: TKey extends `NUXT_PUBLIC_${string}`
? `${TKey extends `NUXT_PUBLIC_${string}`
? TKey
: never} should not prefixed with NUXT_PUBLIC_.`
: TServer[TKey];
});
const client = typeof opts.client === "object" ? opts.client : {};
const server = typeof opts.server === "object" ? opts.server : {};

return createEnvCore<ClientPrefix, TServer, TClient>({
...opts,
Expand Down

1 comment on commit 245f6ad

@vercel
Copy link

@vercel vercel bot commented on 245f6ad Jun 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

t3-env – ./

t3-env-git-main-t3-oss.vercel.app
t3-env.vercel.app
t3-env-t3-oss.vercel.app
env.t3.gg

Please sign in to comment.