0

I have an type with props that can be optional depending on a generic type:

type MyType<R extends Record<string, string> | undefined, A extends string[] | undefined> = {
  record: R
  array: A
}

I have a function that takes a MyType object

const myFunction = <R extends Record<string, string> | undefined, A extends string[] | undefined>(myObject: MyType<R, A>)=>{
  // ... //
}

I want to be able to call myFunction and omit a record in the props if R is undefined, for example

const record = getTheRecord() // Assuming getTheRecord() returns a undefined here
const array = ['a']
myFunction<undefined, string[]>({
  array
})

How can I make some props optional depending on a generic type?

Simon Tran
  • 1,461
  • 1
  • 11
  • 28

2 Answers2

0

You don't need to extend undefined in the extend clause to achieve what you're looking for. If you want to allow "either Record or undefined", where undefined is not explicitly assigned, you can do so using a partial type:

type MyType<R extends Record<string, string>, A extends string[]> = {
  record?: R
  array?: A
}

const myFunction = <R extends Record<string, string>, A extends string[]>(myObject: MyType<R, A>)=>{
  // ... //
}
Slava Knyazev
  • 5,377
  • 1
  • 22
  • 43
  • I need to be able to call `myFunction` with `R` as undefined as so: `myFunction({ array: [] })` – Simon Tran Nov 23 '22 at 05:39
  • I think this is a good answer, and if there's a requirement that you need to manually specify the `R` type argument as `undefined`, it should be written explicitly into the question (right now I don't see any example there where the type argument is manually specified). I certainly wouldn't want to penalize someone for failing to guess unstated requirements. Anyway, if you want `| undefined` in there, you can [certainly do that](https://tsplay.dev/w2pb8m). I'd recommend that OP accepts this answer after editing the question and after the answer is edited to add `| undefined` to match. – jcalz Nov 23 '22 at 16:07
  • The answer simply added `?` to the prop. My question was how to make a prop conditionally optional. `record` needs to be requred if `R` does not extend `undefined` – Simon Tran Nov 23 '22 at 18:44
0

Found this answer: https://stackoverflow.com/a/67630189/6592293

It seems to be working!

type UndefinedToOptional<T> = { [K in keyof T]-?:
  (x: undefined extends T[K] ? { [P in K]?: T[K] } : { [P in K]: T[K] }) => void
}[keyof T] extends (x: infer I) => void ?
  I extends infer U ? { [K in keyof U]: U[K] } : never : never

type MyType<R extends Record<string, string> | undefined, A extends string[] | undefined> = {
  record: R
  array: A
}

const myFunction = <R extends Record<string, string> | undefined, A extends string[] | undefined>(myObject: UndefinedToOptional<MyType<R, A>>)=>{
  // ... //
}

const array = ['a']
myFunction<undefined, string[]>({
  array
})

Simon Tran
  • 1,461
  • 1
  • 11
  • 28