【发布时间】:2021-10-21 12:42:19
【问题描述】:
我看到一个案例,TypeScript 编译器允许我为一个不正确类型的变量赋值。这会导致应该在编译时捕获的运行时错误:
// An interface to represent JSON data stored somewhere.
interface Foo {
a: string,
b: number,
}
interface Boo extends Foo {
c: boolean,
}
// A class that has some of the same fields as Foo, but has more stuff going on.
class Bar {
get frank(): string { return this.a + this.b; }
get a(): string { return 'a'; }
get b(): number { return 5; }
greet() { console.log(this.frank, this.a, this.b)};
}
// Some function that retrieves JSON data from where it is stored. Might be Foo or a different data type that extends foo.
function getIt<T extends Foo>() : T {
return { a: 'hi', b: 38 } as T; // Hard coded for the example.
}
// The compiler emits an error if I try to do this because the type is different from the Foo interface.
const notReallyFoo: Foo = { a: 'a', b: 0, c: true };
// The compiler does let me do this even though Bar is different from Foo, and does not implement/extend Foo.
const notReallyBar: Bar = getIt();
notReallyBar.greet(); // Runtime error because the object does not have the greet method.
是否需要进行一些更改,以便在编译时捕获此类错误?有没有更好的方法来解决这个问题?
【问题讨论】:
-
从 nextwork 中检索 JSON 时,您没有具体的类型。如果你断言你的 JSON 类型不正确,那么所有的赌注都没有了。为避免这种情况,您可以创建类型保护以确保您的数据是正确的形状,或者在极端情况下,使用验证器(例如 github.com/ajv-validator/ajv )来确保 100% 稳健。
-
签名为
<T extends Foo>()=>T的函数(如您的getIt())总是会出现问题。当调用者在运行时不传递任何参数时,你怎么可能安全地实现声称返回调用者想要的任何Foo子类型的东西?您几乎需要使用 type assertion 或 theanytype 来实现编译,然后您故意不安全。 -
你说
Bar is different from Foo, and does not implement/extend Foo但这不是真的。Bar确实实现了Foo;只是没有声明这样做。 TypeScript 的类型系统是structural,不是名义上的。 -
和
The compiler emits an error if I try to do this because the type is different from the Foo interface.也不完全正确。{ a: 'a', b: 0, c: true }与Foo100% 兼容,但编译器有一个类似 linter 的规则,称为 excess property checking,如果您将具有额外属性的 object literal 分配给一个变量或属性会忽略它们。 -
我...认为示例代码和代码 cmets 中发生了很多事情,所以如果没有很多关于 TS 工作原理的解释,我不确定如何回答这个问题。也许您可以减少帖子的数量,只提出一个特定的问题,我们可以回答它?
标签: typescript generics compiler-errors