1

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}}
6
  • What do you need this for? Can you provide a list of inputs and expected outputs? Commented Feb 18, 2020 at 12:25
  • 1
    Do you have finite number of elements? If so you are looking for tuple ['id', 'title'] | ['title', 'id'] Commented Feb 18, 2020 at 12:26
  • This array if for api request fields that user will want to get. Array of strings only (keyof Book). Commented Feb 18, 2020 at 12:32
  • @MaciejSikora how can i make this tuple type from Book? Commented Feb 18, 2020 at 12:33
  • Can I ask why you need tuple/array and not record? Commented Feb 18, 2020 at 12:49

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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'

2 Comments

I thought you want tuple from Union and not other way around
@MaciejSikora i just wanted type connection, if it was possible to make tuple from union, it's will be good, but this will work for me too, just with additional step.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.