elierotenberg / directus-typescript-gen

93 stars 11 forks source link

Every field is optional in generated types #4

Open stpoa opened 1 year ago

stpoa commented 1 year ago

Every field is optional in generated types regardless of settings in Directus.

Any idea why?

aurelienbobenrieth commented 1 year ago

Yeah was wondering the same, this is pretty annoying.

Anoesj commented 11 months ago

I agree it's annoying. However, this is a problem (or decision) on either Directus' end or in the openapi-typescript module. All this module does is fetch Directus' OpenAPI spec and turn it into TS definitions using openapi-typescript. There's not a lot of magic or type transformation going on in this module itself.

sunxyw commented 8 months ago

Because Directus allows you to modify the fields to be retrieved using the fields parameter, not every field will be returned.

HarunKilic commented 7 months ago

Did you guys find any workaround? Or did you find another solution?

sunxyw commented 7 months ago

Did you guys find any workaround? Or did you find another solution?

you may try setting the field to not null, and see if it helps

HarunKilic commented 7 months ago

Did you guys find any workaround? Or did you find another solution?

you may try setting the field to not null, and see if it helps

Even ID seems to be optional. But I'll give it a try.

Frioo commented 1 month ago

Wondering if there's any updates on this. Also a little off-topic, but anyone got a clue how to get properly typed responses for relational fields? Let's say I have a collection like this:

interface Products {
  id?: number;
  title?: string | null
  media?: number | MyMediaItem[] | null
}

where MyMediaItem is the related collection item type. When fetching with fields: ['*"] media should be of type number, but with fields: ["*", "media.*"] I should get MyMediaItem[]. This does not seem to work, and I can't have typing/intellisense for the related item since for typescript it's always number | MyMediaItem[] | null. Quite annyoing, not sure how to tell TS/Directus SDK that it should force one of the available types for a specific query.

Bijig0 commented 1 month ago

Wondering if there's any updates on this. Also a little off-topic, but anyone got a clue how to get properly typed responses for relational fields? Let's say I have a collection like this:

interface Products {
  id?: number;
  title?: string | null
  media?: number | MyMediaItem[] | null
}

where MyMediaItem is the related collection item type. When fetching with fields: ['*"] media should be of type number, but with fields: ["*", "media.*"] I should get MyMediaItem[]. This does not seem to work, and I can't have typing/intellisense for the related item since for typescript it's always number | MyMediaItem[] | null. Quite annyoing, not sure how to tell TS/Directus SDK that it should force one of the available types for a specific query.

Same brother, same...

pomeh commented 4 weeks ago

Hello,

I encounter the same problem, and here are some informations that may help (or not).

First, the OpenAPI spec (OAS) from Directus (/server/specs/oas) does not list which fields are required or not. If OAS don't know it, the spec for /items/whatever/{id} operation JSON response is converted into a TS type with properties as optionnals. But having a field required in Directus only concern the item creation and edition, if you have older items before field foo became required, the field may still be inexistent.

Second, for a given endpoint (for example /items/whatever/{id}), one may decide to include only some fields in the JSON output (directus.request(readItems('whatever', {fields: ["bar"]}))), so even if field foo is required for all items in the collection, this call will only return the bar field. The typings for directus.request and/or readItems could be updated to create a new Type based on which fields are listed, but I guess this needs a fix inside Directus code.

Lastly, even if you include fields * in your REST request, an admin can configure endpoints to retrict which fields are public or not. So the typings used must reflect the correct permissions you have when requesting the API endpoints. If you use the API anonymously, the typings must be the public /server/specs/oas. If you use it with a specific role, typings must be ajusted.

Concerning to composed type problem, one ugly workaround I found so far is to use TypeScript type guards. For example:

function hasAuthor(user?: components["schemas"]["whatever"]["user_created"]): user is components["schemas"]["Users"] {
    return user !== undefined && user !== null && typeof user === 'object' && 'first_name' in user;
}

export default async function MyPage() {
    const whatevers = await directus.request(
        readItems('whatever', {
            fields: ["foo", { "user_created": ["first_name"]}],
        })
    );

    return (
        <div>
            {whatevers.map((whatever) => {
                return (
                    <span key={whatever.id}>{hasAuthor(whatever.user_created) && whatever.user_created.first_name}</span>
                );
            })}
        </div>
    );
}