def of_type(ts):
    """
    >>> of_type({'kind': 'OBJECT', 'name': 'User', 'ofType': None})
    'User'
    >>> of_type({'kind': 'NON_NULL', 'name': None, 'ofType': {'kind': 'SCALAR', 'name': 'String', 'ofType': None}})
    'String'
    >>> of_type({"kind": "ENUM", "name": "ProjectState"})
    'ProjectState'
    """
    if ts.get("kind") == "OBJECT":
        return ts["name"]

    if ts.get("kind") == "INTERFACE":
        return ts["name"]

    if ts.get("kind") == "INPUT_OBJECT":
        return ts["name"]

    if ts.get("kind") == "UNION":
        return ts["name"]

    if ts.get("kind") == "ENUM":
        return ts["name"]

    if ts.get("args"):
        return "Method"

    if ts.get("kind") == "SCALAR":
        return ts["name"]

    subKind = ts.get("type") or ts.get("ofType")
    if not subKind:
        raise ValueError(ts)

    if subKind["kind"] == "LIST":
        subT = of_type(ts.get("type") or ts.get("ofType"))
        return "[{}]".format(subT)

    if subKind["name"]:
        return subKind["name"]

    return subKind["ofType"]["name"]