TypeScript类型守卫和“仅引用类型,但在此处用作值”的问题。

4

我正在使用Typescript 3.2.2,但无法实现最基本的类型保护:

interface Bird {
    fly(): boolean;
}

interface Fish {
    swim(): boolean;
}

function swimIfYouCan(x: Fish | Bird) {
    if ((<Fish>x).swim) {
        return true
    }
}

在 WebStorm 中会产生 Error:(50, 11) TS2693: 'Fish' only refers to a type, but is being used as a value here.,而从 yarn 得到的错误是 SyntaxError: /Users/sea-kent/git/docket-management/webapp/src/App.tsx: Unexpected token (51:8)。需要配置启用此语法吗?


3
如果你在使用TSX,<Fish> 可以作为一个元素 - 使用 x as Fish 替代。例如请参见 https://dev59.com/nFsX5IYBdhLWcg3wHcXA#54614279 和 https://www.typescriptlang.org/docs/handbook/jsx.html。 - jonrsharpe
@jonrsharpe,就是这样,谢谢您。 - Aaron Kent
2个回答

2
有三种不同的方法可以解决您的问题。
  1. 如果您想要强制转换并直接使用它,您必须使用as运算符(如评论中@jonrsharpe所述),例如(x as Fish).swim
  2. 使用in运算符检查是否可用,例如if ('swim' in x)
  3. 最后但并非最不重要的(对于这种情况,在我看来是最好的情况),只需进行实例检查以检查您拥有的实例:if (x instance of Fish)
编辑:没有仔细阅读问题,您无法在运行时检查接口。但是创建一个基于接口的类没有坏处。

2
最后一个不会起作用,因为接口在运行时不存在。 - Cerberus
2
x instanceof Fish gives the same problem 'Fish' only refers to a type, but is being used as a value here. - Aaron Kent
1
如果我只想调用方法,那么 in 就可以正常工作,但是如果我想要将一个 Fish 传递给其他正在检查的东西,它就不行了。我认为 x as Fish 是最好的选择。谢谢。 - Aaron Kent
1
哦,看来他没有仔细阅读问题,因为他正在使用一个接口而不是一个类。 - Nicolas Gehlert

1

检查属性存在性的推荐模式匹配方法是使用in运算符:

interface Bird {
    fly(): boolean;
}

interface Fish {
    swim(): boolean;
}

function move(x: Fish | Bird) {
  if ("swim" in x) {
    return x.swim();
  } else {
    return x.fly();
  }
}

通过使用in运算符,您可以避免断言。

谢谢。这对于这个微不足道的情况是有效的,但如果我想更进一步并实际拥有一个Fish传递给其他东西,我认为x as Fish更符合目标: return (x as Fish).swim !== undefined; }``` - Aaron Kent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接