Type issues iterating over js object keys

Hi, I am trying to figure out how to type a json object that has been parsed and loaded by a js library. I need to be able iterate over some of the json’s object keys, but I am struggling to figure out how to type it properly.

Here is an example of the json that is parsed:


{
  paths: 
  {
    '/favs/all': {
      get: {
        operationId: 'getAllFavs',
        // ...stuff omited
      }
    },
    '/favs/subs': {
      get: {
        operationId: 'getFavSubs',
        // ...stuff omited
      }
    },
  }
}

My code below gives me the following error about the line let httpVerbData = Js.Option.getExn(pathData, "get"):

This has type: OpenApiTypes.pathItemOpject
  Somewhere wanted: option<'a => 'b>
module OpenApiTypes = {
  type openApiOperationObject = {
    operationId: option<string>,
  }

  type pathItemOpject = {
    get: option<Js.Dict.t<openApiOperationObject>>,
    put: option<Js.Dict.t<openApiOperationObject>>,
    post: option<Js.Dict.t<openApiOperationObject>>,
    delete: option<Js.Dict.t<openApiOperationObject>>,
    options: option<Js.Dict.t<openApiOperationObject>>,
    head: option<Js.Dict.t<openApiOperationObject>>,
    patch: option<Js.Dict.t<openApiOperationObject>>,
    trace: option<Js.Dict.t<openApiOperationObject>>,
  }

	type openApi = {paths: Js.Dict.t<pathItemOpject>}
}

type refParserDerefFunc = {
  dereference: (. string, (. Js.nullable<Js.Exn.t>, OpenApiTypes.openApi) => unit) => unit,
}

@module("@apidevtools/json-schema-ref-parser")
external refParser: refParserDerefFunc = "default"

exception DereferenceError(Js.Nullable.t<Js.Exn.t>)

refParser.dereference(."asd", (. err, schema) => {
  if Js.Option.isSome(Js.Nullable.toOption(err)) {
    raise(DereferenceError(err))
  }

  Js.Dict.entries(schema.paths)->Js.Array2.forEach(pathKeyVal => {
    let (pathString, pathData) = pathKeyVal
    
    let httpVerbData = Js.Option.getExn(pathData, "get")
  })
})

Playground link

Ok, I think I found a way to do this using js Object.entries like this:

    let pathDataObjEntries: 't => array<(
      string,
      OpenApiTypes.openApiOperationObject,
    )> = %raw(`Object.entries`)

Full code:

module OpenApiTypes = {
  type openApiOperationObject = {
    operationId: option<string>,
     responses: Js.Dict.t<string>,
  	parameters: array<string>,
  }

  type pathItemObject = {
    get: openApiOperationObject,
    put: openApiOperationObject,
    post: openApiOperationObject,
    delete: openApiOperationObject,
    options: openApiOperationObject,
    head: openApiOperationObject,
    patch: openApiOperationObject,
    trace: openApiOperationObject,
  }

  type openApi = {paths: Js.Dict.t<pathItemObject>}
}

type refParserDerefFunc = {
  dereference: (. string, (. Js.nullable<Js.Exn.t>, OpenApiTypes.openApi) => unit) => unit,
}

@module("@apidevtools/json-schema-ref-parser")
external refParser: refParserDerefFunc = "default"

exception DereferenceError(Js.Nullable.t<Js.Exn.t>)

refParser.dereference(."asd", (. err, schema) => {
  if Js.Option.isSome(Js.Nullable.toOption(err)) {
    raise(DereferenceError(err))
  }

  Js.Dict.entries(schema.paths)->Js.Array2.forEach(pathKeyVal => {
    let (pathString, pathData) = pathKeyVal

    let pathDataObjEntries: 't => array<(
      string,
      OpenApiTypes.openApiOperationObject,
    )> = %raw(`Object.entries`)


    pathDataObjEntries(pathData)->Js.Array2.forEach(
      entry => {
        let (httpVerb, httpVerbData) = entry

        let {operationId, parameters, responses} = httpVerbData
      },
    )
  })
})

Playground link

1 Like