1
// given typings of library

type t1 = string
type t2 = number
type t3 = { [key: string]: number | string | boolean | Array<string | number> | undefined }

interface i1 extends i0 {
    ba: t2,
    bb: t2
}

interface i2 extends i0 {
    ca: t2,
    cb: t2
}

type union = i1 | i2 

interface i0 {
  aa: t1
  fn?: (arg: t3) => boolean
}

// my typings

type t4 = { prop1: string, prop2: number }
type myfn<T> = { fn?: ((arg: T) => boolean) }
type mytype<T> = myfn<T> | Omit<union, 'fn'>
type myNonUnionType<T> = myfn<T> | Omit<i1, 'fn'>

// implementation examples

let obj1: union = {
  aa: 'hello',
    ba: 3,
    bb: 4,
    fn: (arg) => arg.prop1 === arg.prop2.toString()  // error: possible undefined
}

let obj2: mytype<t4> = {
  aa: 'hello',
    ba: 2, // error: ba does not exist
    bb: 3,
  fn: (arg) => arg.prop1 === arg.prop2.toString()
}

let obj3: mytype<t4> = {
  aa: 'hello',
    ca: 2, // error: ca does not exist
    cb: 3,
  fn: (arg) => arg.prop1 === arg.prop2.toString()
}

let obj4: myNonUnionType<t4> = { // works, but only without union
  aa: 'hello',
    ba: 2,
    bb: 3,
  fn: (arg) => arg.prop1 === arg.prop2.toString()
}

I have to work with a typed javascript library. The types t1 - t3, the interfaces i1 and i2 and the type union represent what is given in the library.

The types t4, myfn and mytype are in my code.

The intended usage of the library is like obj1. But if I use it like this, there is the error arg.prop2 is possibly undefined. I know I could test for undefined with arg.prop2?, but this is only an example. In the production code the rather loose typing of t3 gives a lot of unnecessary typecheckings (e.g. if I know there will be an array and want to use an iterator but you can't use iterators with t3)

So to get around this I typed my argument to fn more precise with t4. To get t4 in the object I defined the two types myfn and mytype and then type the object obj2 and obj3 as mytype

In obj2 and obj3 typescript now gives me the error that ba or ca does not exist in type mytype

I was expecting that mytype containes also the stuff from i0 and i1 | i2 but it seems not.

If I just for testing don't use the union type but directly i1 like I did with obj4: myNonUnionType there is no error, but I need to use the union. How can I solve this problem?

I'm not fixed to use the typings like they are now, I just want to "inject" my type t4 in the function fn.

dnmeid
  • 386
  • 3
  • 4
  • 1
    Could you [edit] the code to be a self-contained [mre] suitable for pasting as-is into a standalone IDE so we can see what you're seeing? Right now it's interspersed with text and some type definitions seem to be missing, so it's hard to get started. – jcalz Feb 15 '23 at 15:45
  • Edit done as requested. – dnmeid Feb 17 '23 at 00:26
  • 1
    Don't you want to use `&` instead of `|` in `MyType` and `MyNonUnionType`? If so, your issue seems to be that `Omit` is not distributive in unions and thus the same as [this question](https://stackoverflow.com/a/57103940/2887218). The fix would look like [this playground link](https://tsplay.dev/mxjj1w). Does that fully address your question, or am I missing something? – jcalz Feb 17 '23 at 15:57
  • 1
    @jcalz, that successfully solves the problem. Thank you! – dnmeid Feb 17 '23 at 17:52

0 Answers0