Skip to content

fix(types): support fluent-json-schema - #244

Open
salluexez wants to merge 1 commit into
fastify:mainfrom
salluexez:fix/fluent-schema-types
Open

salluexez wants to merge 1 commit into
fastify:mainfrom
salluexez:fix/fluent-schema-types

Conversation

@salluexez

Copy link
Copy Markdown

Summary

Allow fluent-json-schema schemas to be passed to envSchema without TypeScript errors.

Problem

env-schema supports Fluent Schema objects at runtime and documents that usage, but EnvSchemaOpt.schema only accepted Ajv schema types. Consequently, valid Fluent Schema objects were rejected by TypeScript.

Solution

Add a dependency-free structural FluentSchema type and include it in the accepted schema union. This preserves existing Ajv and TypeBox support without adding a production or peer dependency.

Testing

  • npm run lint
  • npm test — 46 unit tests and 23 type assertions passed; 100% runtime coverage
  • npm pack --dry-run --cache /tmp/env-schema-npm-cache
  • git diff --check

Screenshots / Evidence

Not applicable; this is a TypeScript declaration fix.

Related Issue

Closes #138

Additional Notes

The regression test fails before the fix with TS2322 and passes afterward. There are no runtime changes or compatibility changes for existing schema types.

Signed-off-by: Mohd Salauddin <sallumalik1111@gmail.com>
Copilot AI lite review requested due to automatic review settings August 30, 2026 18:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Comment thread types/index.d.ts

type EnvSchema = typeof envSchema

type FluentSchema = {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

  • why it needs to change: fluent-json-schema's own README documents isFluentSchema as the public detection flag; isFluentJSONSchema is also set on every BaseSchema<T> but is not the documented public contract. The two-field structural type is broader than what the upstream docs promise to set.
  • code suggestion:
    type FluentSchema = { isFluentSchema: boolean }
  • why the suggestion differs: narrows the structural requirement to the single documented public flag; an object with isFluentSchema: boolean is a fluent schema per the upstream README, and the second field does not add coverage the documented contract guarantees.

Comment thread types/index.d.ts

export type EnvSchemaOpt<T = EnvSchemaData> = {
schema?: JSONSchemaType<T> | AnySchema;
schema?: JSONSchemaType<T> | AnySchema | FluentSchema;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

  • why it needs to change: this PR changes the types only. The runtime detection in index.js still uses Symbol.for('fluent-schema-object') + .valueOf(). The structural type is a type-level approximation of what the runtime already accepts, not a new contract, and a future reader of this line could infer that adding a field here changes runtime behavior.
  • code suggestion: add a short // type-only: runtime uses Symbol.for('fluent-schema-object') in index.js above the union, or attach a JSDoc to the FluentSchema type pointing at the runtime path so the two stay in sync.
  • why the suggestion differs: makes the type-only nature explicit at the point of use; prevents a future contributor from "tightening" the type to match a runtime field they think is checked and breaking valid fluent schemas.

Comment thread types/index.tst.ts
const envSchemaTypebox = envSchema<SchemaTypebox>({ schema: schemaTypebox })
expect(envSchemaTypebox).type.toBe<SchemaTypebox>()

const envSchemaFluent = envSchema<EnvData>({

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

  • why it needs to change: this assertion uses S.object<EnvData>() to force the generic T, but fluent-json-schema does not infer T from .prop(...) arguments (unlike TypeBox). Users will not naturally type fluent schemas this way, and the test reads as promising more type inference than fluent-json-schema delivers.
  • code suggestion: either drop this assertion (the optWithFluentSchema block at line 50 already proves the regression fix), or replace it with a .valueOf() assertion that locks in the documented escape hatch from Use with fluent-json-schema now requires to call valueOf in ObjectSchema when using Typescript #138, e.g. expect(S.object().valueOf as unknown as object).type.toBeAssignableTo<JSONSchemaType<EnvSchemaData>>(). If the generic-T path must be exercised, leave a one-line comment that it is a manual-typing witness, not runtime validation.
  • why the suggestion differs: removes the over-claim about fluent-json-schema's type inference; the replacement locks in the workaround the original issue explicitly mentioned, and the regression is still proven by the first assertion.

Comment thread types/index.d.ts
type EnvSchema = typeof envSchema

type FluentSchema = {
isFluentSchema: boolean;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hi @salluexez, thanks for your PR.
I'm not sure about this.
It seems like a Fluent workaround, not really an issue with this package.
In this branch, https://github.com/Puppo/env-schema/tree/test-fluent-schema, I prove that we should reach the same result without touching the codebase.

I'm happy to let you review your pr to add these tests if you'd like.
If you proceed, please also remember to add the test example to the JavaScript tests.

Comment thread types/index.tst.ts
Comment on lines +50 to +53
const optWithFluentSchema: EnvSchemaOpt = {
schema: S.object().prop('PORT', S.number().default(3000).required()),
}
expect(optWithFluentSchema).type.toBe<EnvSchemaOpt>()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
const optWithFluentSchema: EnvSchemaOpt = {
schema: S.object().prop('PORT', S.number().default(3000).required()),
}
expect(optWithFluentSchema).type.toBe<EnvSchemaOpt>()
const optWithFluentSchema = {
schema: S.object().prop('PORT', S.number().default(3000).required()),
}
expect(optWithFluentSchema).type.toBeAssignableTo<EnvSchemaOpt>()

Comment thread types/index.tst.ts
schema: S.object<EnvData>().prop(
'PORT',
S.number().default(3000).required()
),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
),
).valueOf(),

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use with fluent-json-schema now requires to call valueOf in ObjectSchema when using Typescript

4 participants