miyazato
(Kazuki Miyazato)
June 17, 2022, 10:36am
1
Hi community,
Is there a good way to type definition the fetchLinks information?
I think the project retrieved as follows would have access to project.data.creator.data.name.
// getStaticProps()
const project = await client.getByUID<ProjectDocument>('project', uid, {
fetchLinks: ['creator.name', 'creator.face']
})
However, in props, the fetchLinks information is lost because it is only typed ProjectDocument<string>
.
type ProjectProps = {
project: ProjectDocument<string>
}
const Project: NextPage<ProjectProps> = ({ project }) => {
const name = project.data.creator.data.name //Property 'data' does not exist on type 'EmptyLinkField<"Document"> | FilledLinkToDocumentField<"creator", string, never>'.
// Property 'data' does not exist on type 'EmptyLinkField<"Document">'.ts(2339)
return <>...</>
}
How do I keep the fetchLinks information in project
?
Fares
June 17, 2022, 3:21pm
3
Hi @miyazato
Thanks for reaching out.
It seems that the error doesn't concern fetched links but the higher-level data
field as shown in this error
//Property 'data' does not exist on type 'EmptyLinkField<"Document"> | FilledLinkToDocumentField<"creator", string, never>'.
// Property 'data' does not exist on type 'EmptyLinkField<"Document">'.ts(2339)
return <>...</>
}
If that is correct, then can you try to remove the Fetch links and try if it works?
miyazato
(Kazuki Miyazato)
June 18, 2022, 9:01am
4
Hi Fares
Thanks you for your reply.
Sorry, the error message seems to be different due to the simplification.
Below is the code that actually works.
type ProjectProps = {
project: ProjectDocument<string>
}
const Project: NextPage<ProjectProps> = ({ project }) => {
if( !isFilled.contentRelationship(project.data.creator) ) { // Need to validate again, even though it is obvious.
return <></>
}
const creator = project.data.creator
console.log('creator.data.name:', creator.data.name) // This work but show error in VScode
/**
(property) FilledLinkToDocumentField<"creator", string, never>.data?: undefined
Object is possibly 'undefined'.ts(2532)
*/
return (
<></>
)
}
export default Project
export const getStaticProps = async ({ params, previewData }: any /** I don't know what type.🥹 */) => {
const client = createClient({ previewData })
const project = await client.getByUID<ProjectDocument>('project', params.uid, {
fetchLinks: ['creator.name', 'creator.face']
})
if( !isFilled.contentRelationship(project.data.creator) ) {
return {
notFound: true
}
}
return {
props: {
project
},
}
}
I know that creator.data.name is accessible and works, but TypeScript don't know it.
1 Like
Fares
June 24, 2022, 2:05pm
5
Hi @miyazato
Well, I have reported this issue to our dev team, and I will let you know in case of any updates.
Feel free to raise the issue in the open-source project
miyazato
(Kazuki Miyazato)
June 24, 2022, 2:33pm
7
Hi @Fares
Thanks.
The types can be manually typed.
Not ideal, this problem was avoided.
type Simplify<T> = {
[KeyType in keyof T]: T[KeyType]
}
type FetchKeyUnion<T extends string[] | readonly string[]> = T[number] // array to union type
type ProjectWithFetched<U extends FetchKeyUnion<T>> = RelationField<"project", string, Pick<ProjectDocument['data'], U>>
interface FeaturedProjectsDocumentDataProjectsItemFilled<U extends FetchKeyUnion<T>> extends FeaturedProjectsDocumentDataProjectsItem {
project: ProjectWithFetched<U>
}
interface FeaturedProjectsDocumentDataFilled<U extends FetchKeyUnion<T>> extends FeaturedProjectsDocumentData {
projects: GroupField<Simplify<FeaturedProjectsDocumentDataProjectsItemFilled<U>>>
}
type FeaturedProjectsDocumentWithLinks<U extends FetchKeyUnion<T>, Lang extends string = string> = PrismicDocumentWithoutUID<Simplify<FeaturedProjectsDocumentDataFilled<U>>, "featured-projects", Lang>
const projectFetchKeys = ['title', 'featuredMedia', 'abstract'] as const
type TProjectFetchKey = FetchKeyUnion<typeof projectFetchKeys>
export async function getStaticProps({ previewData }: any) {
const client = createClient({ previewData })
const featuredProjects = await client.getSingle<FeaturedProjectsDocumentWithLinks<TProjectFetchKey>>('featured-projects', {
fetchLinks: projectFetchKeys.map(key => `project.${key}`)
})
return { props: { featuredProjects, }, }
}
type Props = {
featuredProjects: FeaturedProjectsDocumentWithLinks<TProjectFetchKey>
}
Fares
July 4, 2022, 8:50am
8
Right, you appear to be using prismic-ts-codegen
.
That tool does not generate TypeScript types for data fetched with fetchLinks
/graphQuery
, so you need to add those types yourself.
And I will keep you up-to-date in case of any changes.
miyazato
(Kazuki Miyazato)
July 4, 2022, 9:10am
9
Hi, @Fares
Ok, I understand prismic-ts-codegen does not have such a generics.
Thank you so much!
1 Like
Hey @miyazato @Fares I ran into this problem and I solved it.
For context, I am also using prismic-ts-codegen
and a GraphQuery.
I looked at the isFilled.contentRelationship
and noticed it accepted some generic type arguments, and this is working for me:
// contentRelationship: <TypeEnum, LangEnum, DataInterface>
if (isFilled.contentRelationship<'blog-author', string, BlogAuthorDocument['data']>(doc.data.authorLink)) {
doc.data.authorLink.data?.avatar;
}
3 Likes
miyazato
(Kazuki Miyazato)
September 12, 2022, 5:59am
13
Hi @eddyvinck95
I used Type Argument and it worked!
Thanks a lot!
const projects = await client.getAllByType<ProjectDocument>('project', {
fetchLinks: ['creator.name', 'creator.face']
})
if( isFilled.contentRelationship<'creator', string, Pick<CreatorDocument['data'], 'name' | 'face'>>(projects[0].data.creator) ) {
projects[0].data.creator.data?.name // It's working well!
}
1 Like