Reputation: 36876
I'm not sure why there is a problem if i use this line as array and how to fix it:
Pick<Author, PickedAuthorFields>[]
If i use never instead of conditional type, than i have another problem with required author field.
Sandbox 3 with optional ? author had another problems...
This ApiResBook generic type is needed for many pages that will make requests to api with different expected output fields based on request.
Maybe there is alternative approach, i can change shape of object if needed.
// Main types as in database - should't be changed
type Book = {
id: string
title: string
visible: boolean
author: string
}
type Author = {
id: string
name: string
}
// Inhereted from types from main
type BookFields = keyof Book
type AuthorFields = keyof Author
// type for generating expected fetch response from API
type ApiResBook<
PickedBookFields extends BookFields,
PickedAuthorFields extends AuthorFields | undefined = undefined,
> = {
book: Pick<Book, PickedBookFields> & {
author: PickedAuthorFields extends AuthorFields ? Pick<Author, PickedAuthorFields>[] : undefined
}
}
// tests
type BookWithAuthor = ApiResBook<'id', 'name' | 'id'>
// should be ok
const bookWithAuthor1: BookWithAuthor = { book: { id: '1', author: [{ id: '1' }] } }
const bookWithAuthor2: BookWithAuthor = { book: { id: '1', author: [{ name: 'Max' }] } }
const bookWithAuthor3: BookWithAuthor = { book: { id: '1', author: [{ name: 'Max', id: '1' }] } } // why error?
Upvotes: 3
Views: 5900
Reputation: 20152
It was a while to figurate out but I think this is the solution:
type Book = {
id: string
title: string
visible: boolean
author: string
}
type Author = {
id: string
name: string
}
// Inhereted from types from main
type BookFields = keyof Book
type AuthorFields = keyof Author
// type for generating expected fetch response from API
type ApiResBook<
PickedBookFields extends BookFields,
PickedAuthorFields extends AuthorFields | null = null,
AuthorObj = {author: Pick<Author, Exclude<PickedAuthorFields, null>>[]}
> = {
book: Pick<Book, PickedBookFields> & (PickedAuthorFields extends null ? {} : AuthorObj)
}
// tests
type BookWithAuthor = ApiResBook<'id', 'name' | 'id'>
type BookWithoutAuthor = ApiResBook<'id'>
// should be ok
const bookWithAuthor0: BookWithoutAuthor = { book: { id: '1' } }
const bookWithAuthor3: BookWithAuthor = { book: { id: '1', author: [{ id: '1', name: 'Max' }] } }
PS. null can be replaced by undefined or any other unit type
Upvotes: 3