0

I'm creating a TS wrapper over a JS embedded to third-party software API which is unmanaged by me. I want to capture as much behavior as even possible in types and interfaces because untyped vanilla JS is pretty hard to get it working in my case.

So, to be more specific:

I have external object and I have an interface which declares functions it has

declare var foo: object  
interface FooContract {
  function doFooStuff: (fooParam: string) => BlaError | Success
  function doBarStuff: (barParam: string) => BlaError | Success
}

I want to check that:

  1. given object foo has fields doFooStuff and doBarStuff.
  2. these fields are functions.
  3. these functions take params I described, if not return meaningful error message, at least check arity.
  4. these functions return data which is described in return type, if not return meaningful error message.

So I actually do understand that 3) and 4) pretty much runtime checks and should be verified by testing, but anyway.

Also sometimes API throws some errors, and I want to describe and signal somehow which error would be returned. Errors mostly strings and POJOs, and i want to assign types to them (preferably nominal ones, at cost of any number of wheel reinventions and dirty hacks).

So far, I came to:

declare var foo: object  
interface FooContract {
  function doFooStuff: (fooParam: string) => BlaError | Success
  function doBarStuff: (barParam: string) => BlaError | Success
}

function isFooContract(x: object): x is FooContract {
  const r = x as FooContract
  return r.doFooStuff !== undefined && (typeof r.doFooStuff) == "function" &&
         r.doBarStuff && (typeof r.doFooStuff) == "function"
}

class FooOps {
  private fooInternal: FooContract
  constructor (_inner: object) {
    if(isFooContract(_inner))  
      this.fooInternal = _inner
    else 
      throw new EverythingIsBrokenException(_inner, "foo object not satisfies listed asserts")
  }
  function doFooStuff(fooParam: string): BlaError | Success {
    const ret = this.fooInternal(fooParam) 
    if(isBlaError(ret)) 
      return ret
    else if (isSuccess)
      return ret
    else 
      throw new EverythingIsBrokenException(ret, "Returned value of Foo.doFooStuff is not error nor success but something unexpected")
  }
}

So there's no 3) at all, and immense amount boilerplate I need to handwrite. Is there kind of codegen/compiler macroextension/compile-time reflection tools to do the stuff for checking existence of fields?

James Z
  • 12,209
  • 10
  • 24
  • 44
Iva Kam
  • 932
  • 4
  • 13

0 Answers0