Open arashi-dev opened 9 months ago
I managed to make it work by adding this to the core code:
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function pick<T extends Record<string, any>, TKeys extends (keyof T)[]>(
obj: T,
keys: TKeys
): Pick<T, TKeys[number]> {
const pickedItems: Pick<T, TKeys[number]> = {} as never;
keys.forEach((key) => {
if (obj.hasOwnProperty(key)) {
pickedItems[key] = obj[key];
}
});
return pickedItems;
}
export function createLazyEnv<
TPrefix extends string | undefined,
TServer extends Record<string, ZodType> = NonNullable<unknown>,
TClient extends Record<string, ZodType> = NonNullable<unknown>,
TShared extends Record<string, ZodType> = NonNullable<unknown>
>(opts: EnvOptions<TPrefix, TServer, TClient, TShared>) {
const lazyEnv = <
TIncludeKeys extends Extract<
keyof TServer | keyof TClient | keyof TShared,
string
>[]
>({
include,
}: {
include: TIncludeKeys;
}) => {
const client =
typeof opts.client === "object"
? pick(opts.client, include)
: ({} as never);
const server =
typeof opts.server === "object"
? pick(opts.server, include)
: ({} as never);
const shared =
typeof opts.shared === "object"
? pick(opts.shared, include)
: opts.shared;
return createEnv<
TPrefix,
Pick<TServer, TIncludeKeys[number]>,
Pick<TClient, TIncludeKeys[number]>,
Pick<TShared, TIncludeKeys[number]>
>({
...opts,
client,
server,
shared,
clientPrefix: undefined as TPrefix,
});
};
return lazyEnv;
}
const lazyEnv = createLazyEnv({
server: {
FOR_PROJECT_A: z.string(),
FOR_PROJECT_B: z.coerce.number(),
COMMON: z.coerce.boolean(),
},
runtimeEnv: process.env,
});
const env= lazyEnv({
include: ["COMMON", "FOR_PROJECT_A"],
});
env.COMMON; // boolean - expected
env.FOR_PROJECT_A; // string - expected
env.FOR_PROJECT_B; // Error - expected
Thanks for sharing @arashi-dev
I just recently started a monorepo project using
create-t3-turbo
which has many apps and many packages and also some of the packages have standalone scripts. each app, package, and script requires some environment variables which have some common env variables (e.g.NODE_ENV
,DATABASE_URL
,FRONTEND_URL
, etc.). For now, I made a util package that exports an env object created bycreateEnv
that stores and parses the common env variables. but here is the problem: some of the common variables may not be used in a few of the scripts or packages. so, I have to still set the variables for the apps, packages, or scripts which even is not needed!I thought maybe it would be great if this
t3-env
project could do something like this:the advantages of this feature can be:
createEnv
boilerplatePS. I tried to make a wrapper for the
createEnv
to do this for me but I had to write it in typescript to keep the variable types. but as I am validating the variables inside.mjs
configuration files such asnext.config.mjs
, I cannot write and import.ts
files inside them.