ZiiMakc
ZiiMakc

Reputation: 36876

typescript array of required items

Is there a way to force all elements in array?

Only requirement is "type connection" to main Book type.

I hope there is some way to make tuple type ['id', 'title'] from Book type generically, as suggested in comments. Or at least array length check...

Sandbox.

type Book = {
  id: string
  title: string
  visible: boolean
  author: string
}

type BookFields = keyof Book

type BookFieldsExtract<ExtractedFields extends BookFields> = Extract<BookFields, ExtractedFields>

const arr: BookFieldsExtract<'id' | 'title'>[] = ['id'] // how to force error if title not inclided in array?

Use case:

type SelectedBookFields = BookFieldsExtract<'id' | 'title'> 
type ApiRes = ApiResBook<SelectedBookFields> // {book: {id: string, title: string}}

 const bookFields: SelectedBookFields[] = ['id', 'title'] // i just don't want to forget some fields when making request

  const response = await fetchAPI<ApiReqBookBody, ApiRes>(
    'book',
    { fields: { book: bookFields } }
  ) // response type is {error: true} | {book: {id: string, title: string}}

Upvotes: 1

Views: 1571

Answers (2)

ZiiMakc
ZiiMakc

Reputation: 36876

After some search, found a way that works for my use case:

const bookFields: ['id', 'title'] = ['id', 'title']
type BookFields = typeof bookFields[number] // 'id' | 'title'

Upvotes: 0

Maciej Sikora
Maciej Sikora

Reputation: 20162

I dont know if it will work for you, but I would create some value constructor for this tuple with some overloads in order to guide the dev. Consider:

function makeArrFromKeys<T, A extends keyof T>(obj: T, key1: A): [A]
function makeArrFromKeys<T, A extends keyof T, B extends keyof Omit<T, A>>(obj: T, key1: A, key2: B): [A, B]
function makeArrFromKeys<T, A extends keyof T, B extends keyof Omit<T, A>, C extends keyof Omit<T, A | B>>(obj: T, key1: A, key2: B, key3: C): [A,B,C]
function makeArrFromKeys<T, K extends keyof T>(obj: T, ...keys: K[]): K[] {
    return keys;
}

const book: Book = {
    id: 'i',
    title: 't',
    visible: true,
    author: 'a'
}
const arr = makeArrFromKeys(book, 'id', 'author', 'title')
// arr has type ['id', 'author', 'title']

Our function is extends to three keys, but if you will follow overloads you can go further. Function will make the tuple exactly how you wanted - keys are unique and if you provide you need 'id', 'title' you will get ['id', 'title'].

I would name it compromise between a crazy type which probably we can do, and just maintainable and safety code.

Upvotes: 1

Related Questions