sikanhe / gqtx

Code-first Typescript GraphQL Server without codegen or metaprogramming
458 stars 13 forks source link

How can the resolveType function of unionType or interfaces isTypeOf be made more type-safe? #21

Open n1ru4l opened 4 years ago

n1ru4l commented 4 years ago

For interfaces, the best thing to do is using isTypeOf.

E.g.

const isTypeOf = (src: any) => src?.type === "Operator"

With a library such as io-ts the stuff can be even "more" save:

import { flow } from "fp-ts/lib/function";
import * as t from "io-ts";
import * as E from "fp-ts/lib/Either";

const NoteModel = t.type({
  id: t.string,
  title: t.string,
  content: t.string,
  createdAt: t.number,
  updatedAt: t.number,
});

const isTypeOf = flow(
  NoteModel.decode,
  E.fold(
    () => false,
    () => true
  )
);

The drawback of this is, that the type-safety does happen while executing the code not while compiling it. I wonder whether there are other solutions worth exploring.

For a union type we have the same "issue":

const resolveType = (input) => {
  if (isTypeOfNote(input)) { 
    return GraphQLNoteType;
  } else if (isTypeOfImage(input)) {
    return GraphQLImageType;
  }
  throw new Error("Could not resolve type.");
}

I mentioned some more stuff related to this in https://github.com/sikanhe/gqtx/issues/9

sikanhe commented 4 years ago

This is hard because we don't control the actual execution. If we do - then there is a way to make the resolution of an abstract output type to require the Value and its Object Type that it maps to.

Then you don't even need "resolveType" or "isTypeOf" at all!

Here is an example of how to implement that idea:

https://www.typescriptlang.org/play?#code/C4TwDgpgBA8gRgKwgY2AFXBAPAZQE7IB8UAvFAN4BQUNUA1gJYB2AJgFxQBE8SqnANNVpMAhgFsIHAM7A8zAOaDaUAGYMIAGxZSOAQTx4RILAAopBDvmQBKUsRFMQhJbRFwZh1Dqj7Dx3e6yIqgYkFgOToSUAL4A3JSUoJBQAKpMDAD2TKHQZFTKjKwcnGmZTAJCNBJicBB43r5GWDwo6JhYAK5MdEwZAO5MhFFxCUnQAR7BbWEAkkzAdSrBEABy4hDEeZX0zOxccwt4S8gQnFAAPlylWRXKohLSsgouVRA1dQ0GTS0h7RFDLygIhYLByHFwBEIJgyiDBsEQrRyEKIthIxBMZgsUCsqOIEyCqAAaiINB1sAdFss1hJ+NjIdYYvFEpgfIFPMBiaTyfNKSdqRBaVZSEDHJsKNtmIdjpJWZNfrMeUcqetnNtkFlkHgINMZT8dciosoAG4ksmWAjxEaUDTaqDIAAWInZdT0bKmSM4AGFHc68JwxflaIU9pwKUqTrdhOtit6nVM6mHpZHXu96hwANoAXUBwNBmGhiFsgeUNGA9oYUgAdNVavVK2AOlJ7QWENZ4iXaDCEJW3HLgFWG02TGWK23tsotcAOngmFBMTY7OKOx3J9PZ8Xlx3JbyZSOpIDN8p1UxNdq4V2D4eaCaudICJeO9Fx7QRson1axlAABIdMQOYUbvcMoeAojIJDawBQPav4OBwepIuQQGPHITDyNEAbbMGxR6smUBIVwP5-tkmC4WomjaBm2bbL2BL9pRYGUMeMhQTBTC6FIsa+sKDpxqgdQ9iCOQmNBRFjpQAD04lQAAIhkEBSEwADkkF9BkeB0FAtTICIjbQH00AQAAHpAqBQMAGRQKuM5AlAYDBHQEAsECbqmTeZpQNatrMDeDAsAASvJGQaEadTCvOHDkHh0ZQCBqHRNYrp9pyZJYF6Prxn6mzEBuVmzuYyCWgkklQAA6mpdBSJ5kFalIQUhXgYX5RFUUPDFTxxQlsq0cl2Bpbxhz+ouOXamuLFEexnEZfOY5PkAA