typescript 关于class属性类型定义被属性默认值覆盖的问题及解决方式
问题来源于 React.component的第二个参数的类型定义问题,我构建了以下简化demo,方便描述问题:
class P<STATE> {
public state: STATE;
}
interface Obj {
arr: Obj[];
}
class Test1 extends P<Obj> {
public state = {arr: []};
func(obj: Obj) {
this.state.arr.push(obj);// 这里ts在obj上抛错 Error:(51, 29) TS2345: Argument of type 'Obj' is not assignable to parameter of type 'never'.
}
}
这里主要产生的问题是,我们认为 this.state.arr 应该是Obj[] 类型,所以可以往里面push进去Obj类型的数据,然而this.state.arr却被识别为never[]类型,所以push会抛错。
分析后,发现虽然Test1的state在设置默认值的时候可以使用父类 P 中state的类型定义,但是,在函数中 this.state的类型定义却是使用 默认值 {arr: []} 的类型推断。推断出的类型为{arr:never[]}。
所以产生以上问题。
于是,我们可以这样处理:
class Test2 extends P<Obj> {
public state: Obj = {arr: []}; // 子类同时定义state类型为Obj
func(obj: Obj) {
this.state.arr.push(obj);
}
}
但是这就导致Obj需要定义两次。
我们又注意到,在构造函数中直接赋值,也可以解决该问题:
class Test3 extends P<Obj> {
constructor() {
super();
this.state = {arr: []}; // 直接在constructor中赋值
}
func(obj: Obj) {
const str: string = this.state;
this.state.arr.push(obj);
}
}
但是写起来是比较麻烦的,每次都要写构造函数。
最后,我们按赋值的思想,考虑使用中间类方式:
// 中间类,继承P<T> 这里P类通常为第三方类,如React.Component
abstract class Middle<T> extends P<T> {
protected constructor() {
super();
if (this.initState) {
this.state = this.initState();
}
} abstract initState(): T;
} class Test2 extends Middle<Obj> {
initState() {// 通过方法来初始化state
return {arr: []};
} func(obj: Obj) {
const str: string = this.state;
this.state.arr.push(obj);
}
}
我们在中间类中定义了构造函数来默认调用initState函数,然后让state的初始值作为函数的返回值,可以解决属性默认值的类型覆盖了父类对属性参数的定义。
引进来的代价是我们需要一个中间类。
不过,考虑中间类的引入,可以带来比较多的扩展性,权衡之下,还是可取的。
typescript 关于class属性类型定义被属性默认值覆盖的问题及解决方式的更多相关文章
- ReferenceError: Error #1069: 在 spark.components.RadioButtonGroup 上找不到属性 label,且没有默认值
1.错误描写叙述 ReferenceError: Error #1069: 在 spark.components.RadioButtonGroup 上找不到属性 label,且没有默认值. at Ch ...
- Java 创建数组的方式, 以及各种类型数组元素的默认值
①创建数组的方式3种 ①第1种方法 public class MyTest { public static void main(String[] args){ //method 1 int[] arr ...
- MySql折腾小记二:text/blog类型不允许设置默认值,不允许存在两个CURRENT_TIMESTAMP
From: http://www.cnblogs.com/cyq1162/archive/2011/05/17/2049055.html 在 CYQ.Data 数据框架的反向工程中,遇到MySQL的问 ...
- C++入门经典-例9.5-为具体类型的参数提供默认值
1:默认模板参数是指类模板中由默认的数据类型作为参数的参数,在模板定义时,还可以为默认的数据类型声明,变量,并为变量赋值.代码如下: // 9.5.cpp : 定义控制台应用程序的入口点. #incl ...
- mysql5.7 date类型无法设置'0000-00-00'默认值
现象: mysql5.7之后版本datetime默认值设置'0000-00-00',出现异常:Invalid default value for 'create_time' 原因: mysql5.7之 ...
- Swift学习之方法定义参数有默认值的时候
func testParms(first fir:String, options opt:JSONSerialization.ReadingOptions = []) -> Bool { ret ...
- odoo开发笔记 -- 模型字段定义中设置默认值
例如: company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env['res ...
- SpringMVC,Controller的返回页面类型以及路径设置默认值
一般设置在spring-servlet.xml里面设置 <!-- 对转向页面的路径解析.prefix:前缀, suffix:后缀 --> <bean class="org. ...
- java字符串转换数值类型出现异常赋予默认值
http://blog.csdn.net/w47_csdn/article/details/77855126 可以自定义工具方法,例如: public static int parseInt(Stri ...
随机推荐
- requirejs官网
http://www.requirejs.cn/
- 国内环境安装k8s
环境准备 1. 配置/etc/hosts文件,将所有机器配置成通过主机名可以访问. 2. 如果环境中有代理,请一定要在环境变量中将no_proxy配置正确. 3. master还需要执行下面的命令 ...
- 关于Redis处理高并发
Redis的高并发和快速原因 1.Redis是基于内存的,内存的读写速度非常快: 2.Redis是单线程的,省去了很多上下文切换线程的时间: 3.Redis使用多路复用技术,可以处理并发的连接.非阻塞 ...
- 基于Flask的Web应用程序插件式结构开发
事实上,很多应用程序基于插件式结构开发,可以很方便了扩展软件的功能,并且这些功能完全可以依托于第三方开发者,只要提供好接口和完备文档,比如wordpress.谷歌火狐浏览器等. Python这样的动态 ...
- 深入理解Java虚拟机(第二版)中《长期存活对象将进入老年代》的实践
- JS 自由变量---JS 学习笔记(三) 补充
自由变量:在 A 中作用域要用到的变量 x,并没有在 A 中声明,要到别的作用域中找到他,这个变量 x 就是自由变量.代码示例如下: var x = 20; function A (b) { ret ...
- Demo整合
1.图片上传: https://github.com/842549829/WebUploader 2.百度编辑器: https://github.com/842549829/Ueditor 3.安卓 ...
- react state成员
组件中包括state,props与render成员函数. react中,主要通过定义state,根据不同state渲染对应用户界面. 过程调用了成员函数setState(data,callback). ...
- JVM垃圾回收(三)- GC算法:基础
GC算法:基础 在介绍GC算法在实际场景中的实现之前,我们先定义一些必要的术语,以及GC算法的基本准则.具体的细节会因收集器的不同而稍有区别,但是基本上来说,所有的收集器会关注以下两个方面: 找出所有 ...
- 毕设记录(ajax第一次请求失败,之后成功的问题)
解决方法:将button标签的type属性改为button,而不是submit,将会解决此问题,至于原因,,,还是没太搞清楚..