directus-typescript-gen icon indicating copy to clipboard operation
directus-typescript-gen copied to clipboard

Every field is optional in generated types

Open stpoa opened this issue 1 year ago • 9 comments

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

Any idea why?

stpoa avatar May 25 '23 11:05 stpoa

Yeah was wondering the same, this is pretty annoying.

aurelienbobenrieth avatar May 30 '23 14:05 aurelienbobenrieth

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.

Anoesj avatar Aug 04 '23 08:08 Anoesj

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

sunxyw avatar Oct 15 '23 03:10 sunxyw

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

HarunKilic avatar Nov 17 '23 19:11 HarunKilic

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

sunxyw avatar Nov 17 '23 20:11 sunxyw

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.

HarunKilic avatar Nov 17 '23 20:11 HarunKilic

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.

Frioo avatar May 12 '24 14:05 Frioo

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...

Bijig0 avatar May 13 '24 23:05 Bijig0

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>
	);
}

pomeh avatar Jun 03 '24 15:06 pomeh