【发布时间】:2017-09-15 01:13:40
【问题描述】:
我尝试了一种对我来说似乎很奇怪的行为。
让我们考虑以下示例 (test it in Typescript playground):
abstract class FooAbstract {
abstract bar() {}
}
class Foo extends FooAbstract {
bar() {
return { bar: 'bar' };
}
}
class FooMaker<FOO extends FooAbstract> {
constructor(public foo: FOO) {}
bar() {
return this.foo.bar();
}
baz = () => {
return this.foo.bar();
}
}
let foo = new Foo();
let result = foo.bar();
let foomaker = new FooMaker(new Foo);
let foo2 = foomaker.foo; // Type "Foo", OK
let result1 = foomaker.foo.bar(); // Type "{bar: string}", OK
let result2 = foomaker.bar(); // Type "{}", ???
let result3 = foomaker.baz(); // I've seen comments about using a lambda... Not better
result2 和 result3 的类型类似于抽象 bar 函数 ({})。似乎this 没有解析为具体类Foo,而是解析为抽象类FooAbstract。而foo2 的类型表明foo 类属性已正确解析。
发生了什么事?我做错了什么吗?
更新
事后考虑,这个案例可以这样重新表述 (Test it in Typescript playground):
class Foo {
bar() {
return { bar: 'bar' };
}
getThis(): this {
return this
}
}
class Wrapper {
bar<FOO extends { bar(): {} }>(foo:FOO) {
return foo.bar();
}
}
let wrapper = new Wrapper();
let result = (new Foo()).bar();
let result2 = wrapper.bar(new Foo());
result 的类型为 {bar:string}result2 的类型为 {}(来自界面)。wrapper.bar 的类型为 Wrapper.bar<Foo>(foo: Foo): {}
通过这个示例,更清楚的是,即使知道FOO 的类型为Foo,Typescript 使用FOO 定义而不是其显式类型作为bar 返回类型。
更新 2
好吧,在与打字作斗争时,我想我升级了。这个概念确实是 Typescript 中的隐式类型不遵循任何继承模型,即使在推导类型时也是如此。好吧,我仍然想知道为什么或它会改变,但我必须应对“它就是那样”。所以在这种情况下,类型必须是明确的。
我找到了一种更简单的方法来编写他的示例 (try it in Typescript playground):
abstract class FooAbstract {
abstract bar(): {}
}
class Foo extends FooAbstract {
bar() {
return { bar: 'bar' };
}
}
class FooMaker<FOO extends FooAbstract, BAR> {
constructor(public foo: FOO & { bar: () => BAR } ) {
}
bar():BAR {
return this.foo.bar() as BAR;
}
}
let foomaker = new FooMaker(new Foo());
let result = foomaker.bar();
result 获取类型 {bar:string} 并且无需将泛型放在任何地方。通过使用泛型引用接口,FooMaker.constructor 参数类型中的内容可以变得更简洁。
【问题讨论】:
-
嗯,将
const p = str => console.log(JSON.stringify(str)); p(result2); p(result3); p(result4);添加到您的测试中会将3 x {"bar":"bar"}添加到控制台中。无法重现您正在谈论的问题。请指教 -
@jevgenig 这不是关于值,而是关于它们的类型(以及因此类型检查、完成等......)。要观察问题,请单击 Typescript 游乐场链接(或粘贴到 IDE,例如 VSCode 或 WebStorm)并将鼠标光标放在相关变量上。
-
我现在明白了,感谢您的澄清。
result2具有any类型,因为abstract bar在您的FooAbstract类中没有定义返回类型。尝试将其更改为abstract class FooAbstract { abstract bar(): { bar: string }; } -
@jevgenig 感谢您的建议。但是我不知道如何使它工作。而是更好地理解泛型能做什么和不能做什么,以及设计限制。
标签: generics typescript abstract typescript-typings