隐式扩展TypeScript中的JavaScript类属性
假设我在JavaScript中有这些类,我正在尝试将它们转换为TypeScript:隐式扩展TypeScript中的JavaScript类属性,javascript,typescript,class,Javascript,Typescript,Class,假设我在JavaScript中有这些类,我正在尝试将它们转换为TypeScript: 类狗{ 标签={ 巴克:是的, }; } 帕格犬{ 标签={ …这个标签, 哼:是的, }; } 常数帕格=新帕格(); 但是,TypeScript中的相同代码将产生以下错误: error TS7022: 'tags' implicitly has type 'any' because it does not have a type annotation and is referenced directly
类狗{
标签={
巴克:是的,
};
}
帕格犬{
标签={
…这个标签,
哼:是的,
};
}
常数帕格=新帕格();
但是,TypeScript中的相同代码将产生以下错误:
error TS7022: 'tags' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
这里的错误很明显。我在重新定义标记时使用了这个
,所以TypeScript被打乱了
有没有别的办法来安抚打字脚本?到目前为止,我想到的唯一方法是按照错误提示的方式,显式地键入它。然而,在更大的类型定义中,它变得重复
在一天结束时,我有一些类,它们的属性是定义的键/值对的对象。每个子类扩展super的对象并添加额外的键/值。即使您知道Pug
的tags
属性依赖于Dog
的tags
属性,编译器仍将tags={…this.tags}
视为循环,因此无法确定它将是什么类型。如果需要,您可以显式地注释Pug
的标记
属性,如:
class PugExplicit extends Dog {
tags: { snorted: boolean, barked: boolean } = {
...this.tags,
snorted: true,
};
}
但这很麻烦。另一种方法是确保标签中的this
初始值设定项的类型为Dog
,而不是Pug
:
class Pug extends Dog {
tags = {
...(this as any as Dog).tags,
snorted: true,
};
}
这具有预期的效果,即推断Pug
的标记属于{snorted:boolean,barked:boolean}
类型,而无需显式注释。(我不知道为什么我需要通过any
使用this as any as Dog
来断言,而不仅仅是this as Dog
。但是,如果没有中间类型,编译器仍然抱怨循环性。我想this
通过一个断言而不是两个断言来持续存在?)
您将继承与合成混为一谈,这就是为什么Typescript不喜欢您所做的
最优雅的方式是像React那样做
每次扩展类时,都会将要添加的属性作为泛型传递
由于某些原因,仅在使用构造函数时有效。但是也许其他人可以给你一个更好的方法
class Dog<T = {}> {
tags = {
barked: true,
} as {barked: boolean} & T;
}
class Pug extends Dog<{snorted: boolean}> {
constructor() {
super();
this.tags = {
...this.tags,
snorted: true,
};
}
}
const pug = new Pug();
类狗{
标签={
巴克:是的,
}as{barked:boolean}&T;
}
帕格犬{
构造函数(){
超级();
此参数为.tags={
…这个标签,
哼:是的,
};
}
}
常数帕格=新帕格();
你说得很对,但是你需要扩展超级
的标签,而不是这个
class Pug extends Dog {
tags = {
...super.tags, // <-- change from 'this' to 'super'
snorted: true,
};
}
class帕格犬{
标签={
…super.tags,//首先,这是一个简单的解决方案
类标签{
吠叫=正确;
}
类PugTags扩展了DogTags{
snoted=true;
}
班犬{
标签=新的狗标签();
}
帕格犬{
标签=新的PugTags();
}
说实话,我不是这个解决方案的超级粉丝。但它正确地模拟了我想要的原始问题,没有使用任何太“黑客”的东西,比如像任何
TypeScript强制一样抛出一堆
Jorjon正确地指出,我正在尝试用继承修复组合范式。如果我可以,更好的、仅继承驱动的答案应该是:
类狗{
tagBarked=true;
}
帕格犬{
tagSnorted=true;
}
典型的类继承将自动继承这些属性,因此不需要任何恶意代码。但是对于我正在从JS更新到TS的大型代码库,此解决方案将不起作用,因为对于Pug
类,它总是被称为Pug.tag.snorted
,并且通常也是动态的在上节课上,我可以开始解决上面提到的范例问题,但一步一个脚印
最后,对于未来的读者,这里还有一个选项没有提到:
class Dog {
getTags = () => ({
barked: true,
});
tags: ReturnType<this["getTags"]> = this.getTags() as any;
}
class Pug extends Dog {
getTags = () => ({
...super.getTags(),
snorted: true,
});
}
类狗{
getTags=()=>({
巴克:是的,
});
tags:ReturnType=this.getTags()如有;
}
帕格犬{
getTags=()=>({
…super.getTags(),
哼:是的,
});
}
在标记上的动态显式键入对我来说很不方便,所以这就是为什么我没有使用它作为我的解决方案。另外,我正在寻找隐式类型。也许这种方法的见解对其他开发人员有用。其中说…this.events
,你的意思是…this.tags
,对吗?不。你对e使用this
,您没有声明属性的类型(并且也无法推断)让人感到不安。是的,显式键入它!@Jorjon是的,很抱歉造成混淆。我正在修剪这个玩具示例的实际代码,但不小心将错误留在了。谢谢。是的,后面的选项更好。它实际上是我当前使用的,但是作为任何部分最近在我的代码库中导致了一个模糊的错误,所以我正在尝试查看是否存在错误有更好的解决方案可以重构我的代码库。谢谢你的建议。它确实感觉正确,但似乎TypeScript中存在一个bug。super.tags
在本例中将未定义
到运行时,因此实际上没有传播任何内容。要测试,只需添加console.log(pug.tags.barked)
在你链接的脚本的末尾。你会看到TypeScript认为它将是布尔型类型,而实际上它是未定义的,因为狗的标签实际上没有散开。super
只能访问方法,而不能访问属性。当,我认为这会奏效。因为你指出super
>只能访问方法,也许您可以在子类想要访问时为它们提供一个受保护的方法