directus-typescript-gen
directus-typescript-gen copied to clipboard
Every field is optional in generated types
Every field is optional in generated types regardless of settings in Directus.
Any idea why?
Yeah was wondering the same, this is pretty annoying.
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.
Because Directus allows you to modify the fields to be retrieved using the fields
parameter, not every field will be returned.
Did you guys find any workaround? Or did you find another solution?
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
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.
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.
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 withfields: ['*"]
media
should be of typenumber
, but withfields: ["*", "media.*"]
I should getMyMediaItem[]
. This does not seem to work, and I can't have typing/intellisense for the related item since for typescript it's alwaysnumber | 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...
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>
);
}