1
type GraphQLType =
    | GraphQLInt
    | GraphQLList<any>
    | GraphQLNonNull<any>;

interface GraphQLInt {
  int: number
}

interface GraphQLList<T> {
  x: string
}

interface GraphQLNonNull<T> {
  x: string
}

declare function isInt(type: GraphQLType): type is GraphQLInt;
declare function isList(type: GraphQLType): type is GraphQLList<any>;
declare function isNonNull(type: GraphQLType): type is GraphQLNonNull<any>;

function doIt(t: GraphQLType) {
  if (isInt(t)) {
    return t.int
  }

  if (isList(t)) {
    // t: GraphQLList<any> | GraphQLNonNull<any>
    return t.x
  }

  // t: never

  if (isNonNull(t)) {
    return t.x
  }
}

上面的示例在 isNonNull() 块中导致错误,因为它确定 t 的类型为 never。在 isList() 块中,t 具有 GraphQLList 和 GraphQLNonNull 两种类型。这两种类型在结构上是相同的。这是此处此处描述的相同问题还是实际上是一个错误?

它应该起作用的原因是因为 isList() 是 GraphQLList 而不是 GraphQLNonNull 的类型保护,并且在运行时它将为 List 返回 true,为 NonNull 返回 false,但 typescript 似乎并不代表相同的想法。

4

1 回答 1

1

类型保护将通过将变量的类型缩小到可分配给受保护类型的任何内容来工作

前任:

function isString(s: any) : s is { o: string } {
    return typeof s.o === 'string'; 
}

let s!: number | { o: 'a', n: number } | { o : 'b', b: boolean};
if(isString(s)) {
    s // { o: 'a', n: number } | { o : 'b', b: boolean}
}

联合中缩小到的两种类型if不完全属于受保护类型,但可以分配给它,因此两种类型最终都属于缩小类型,而number不是,因为它不能分配给{ o : string }

将相同的逻辑应用于您的示例,对于 typescript 来说,名义上的不同类型并不重要,因为两者GraphQLListGraphQLNonNull可以相互分配,任何守卫都会选择这两种类型。

正如@jcalz 在评论中指出的那样,您能做的最好的事情就是以某种不会产生太大影响的方式使类型在结构上不兼容。最简单的方法是为每个接口添加一个可选的唯一符号:

type GraphQLType =
    | GraphQLInt
    | GraphQLList<any>
    | GraphQLNonNull<any>;

interface GraphQLInt {
    int: number
}

interface GraphQLList<T> {
    x: string
    readonly __u?: unique symbol;
}

interface GraphQLNonNull<T> {
    x: string
    readonly __u?: unique symbol;
}

declare function isInt(type: GraphQLType): type is GraphQLInt;
declare function isList(type: GraphQLType): type is GraphQLList<any>;
declare function isNonNull(type: GraphQLType): type is GraphQLNonNull<any>;

function doIt(t: GraphQLType) {
    if (isInt(t)) {
        return t.int
    }

    if (isList(t)) {
        // t: GraphQLList<any>
        return t.x
    }

    // t: GraphQLNonNull<any>

    if (isNonNull(t)) {
        return t.x
    }
}

编辑

您注意到类型来自GraphQL您可以使用模块扩充和接口合并来扩展接口。

于 2018-07-26T20:56:42.023 回答