Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No way to get description and title of key in Record #601

Closed
npdev453 opened this issue Sep 23, 2023 · 6 comments
Closed

No way to get description and title of key in Record #601

npdev453 opened this issue Sep 23, 2023 · 6 comments

Comments

@npdev453
Copy link

npdev453 commented Sep 23, 2023

Currently working on totally documentation module in pair with TypeBox and Nominal Types (cutted) and stuck with one problem:

When Type.Record used then all annotations fields of the key missed in result scheme.

Example uno:

    const timeDef = Type.String({ description: 'Time String in ISO-...' })
    const input = Type.Record(
        timeDef,
        Type.Boolean({ description: 'Was stormy?' })
    );

And dirty isolated use-case, where ??? can't be filled by anything:

   const documentation = `
      {
        //  ???  :  ${input.patternProperties['^(.*)$'].description}
        [key: string]: ${input.patternProperties['^(.*)$'].type}
      }
   `

Seems like there a nothing about it in JSON Schema, but maybe TypeBox can be little patchy in this point?
(or maybe yo help to describe problem for passing it into the pro-parental specification?)

Also I'll be able to make PR if solution will be proposed.

@npdev453
Copy link
Author

Monkey-patch workaround:

const RawRecord = Type.Record;
Type.Record = (...args: Parameters<typeof RawRecord>) => {
    const result = RawRecord(...args);
    result.__keySchema = args[0];
    return result;
};

@sinclairzx81
Copy link
Owner

@npdev453 Hi

Monkey-patch workaround:

const RawRecord = Type.Record;
Type.Record = (...args: Parameters<typeof RawRecord>) => {
    const result = RawRecord(...args);
    result.__keySchema = args[0];
    return result;
};

Unfortunately, there's no standard way to express metadata on a records key as the record key is a computed regular expression string derived from types (and assigned as patternProperties), so there's no location to assign extra metadata. Also, it wouldn't be possible to default add __keySchema as this property would be unknown to the Json Schema vocabulary (and would actually break implementations which are strictly limited to the specification)

However, if you need to assign non-standard schema information for the key (as per __keySchema) you can do so in the following way without having to monkey patch the type.

const K = Type.String()
const V = Type.Number()
const R = Type.Record(K, V, { __keySchema: K })

// const R = {
//   __keySchema: { type: 'string', [Symbol(TypeBox.Kind)]: 'String' },
//   type: 'object',
//   patternProperties: { '^(.*)$': { type: 'number', [Symbol(TypeBox.Kind)]: 'Number' } },
//   [Symbol(TypeBox.Kind)]: 'Record'
// }

TypeBox validators are permissive of additional extra data, however validators such as Ajv will require you to add __keySchema as a keyword when validating under strict.

Hope this helps
S

@npdev453
Copy link
Author

npdev453 commented Sep 24, 2023

Nah, want to avoid any duplications and implementation disclosures for end-users.

Seems it will be looks like this (to be dropped before validation):

const __keySchema = new Symbol();
const RawRecord = Type.Record;
Type.Record = (...args: Parameters<typeof RawRecord>) => {
    args[2] = { [__keySchema]: args[0],  ...(args[2] || {}) };
    return RawRecord(...args);
};

(with hardcore maintenance in future, but it's a price)

Also, I just created an issue in JSON Schema Spec, that you can support as popular library or help to purpose solution, of course if you seen there a problem and interesting to resolve in nearest five years.

@sinclairzx81
Copy link
Owner

@npdev453 Heya,

Going to close up this issue as there isn't anything actionable in TypeBox at this time.

Also, I just created an issue in JSON Schema Spec, that you can support as popular library or help to purpose solution, of course if you seen there a problem and interesting to resolve in nearest five years.

Just had a quick read over the issue you posted on the Json Schema Spec. Just be mindful that the Json format itself doesn't support keys other than string (as encoded property keys), and that Json Schema is first and foremost a specification to constrain the capabilities of Json, not TypeScript.

I do think a larger discussion with respect to designing a formal specification for runtime typescript type representation should take place (which would be distinct of Json Schema), but as it stands, there are no formal specifications or efforts to establish such a specification at this time. Establishing a formal specification should take place in the wider community (and not be specific to TypeBox, Json Schema or the schematics it implements).

I do think Json Schema provides a good basis for what such a specification should look like (and is partially why TypeBox adopts Json Schema and extends it for a few JavaScript specific constructs), however again, at this time, efforts to define an idealized specification to capture the semantics of TypeScript at runtime does not exist, making this issue largely non-actionable.

Will keep an eye on the issue you posted, but will close off this one for now.
All the best
S

@npdev453
Copy link
Author

@sinclairzx81,

Got an answer, seems like there already exists thing about it:

https://json-schema.org/understanding-json-schema/reference/object.html#id9
https://ajv.js.org/json-schema.html#propertynames

But currently its not possible to use until #490 will be resolved?

@sinclairzx81
Copy link
Owner

@npdev453 Well, you can implement propertyNames using the following.

import { Type } from '@sinclair/typebox'

const T = Type.Unsafe<Record<string, boolean>>({
  type: "object",
  description: "Was Windy Record",
  patternProperties: {
    "": { type: "boolean" }
  },
  propertyNames: {
    description: "The date it was windy",
    $comment: "'type: string' is implicit because a property name isn't allowed to be anything else in JSON",
    format: "date"
  }
})

type T = Static<typeof T> // Record<string, boolean>

However you will need to use Ajv to validate as TypeBox's validators will only operate on patternProperties and will not take into account the propertyNames. This may be addressed in #490 (though that issue is more specific to adopting Draft 2012-12 representations which may or may not be feasible depending on 2012-12 adoption external to TypeBox)

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

No branches or pull requests

2 participants