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 ...
随机推荐
- 使用pynlpir增强jieba分词的准确度
在使用jieba分词时,发现分词准确度不高.特别是一些专业词汇,比如堡垒机,只能分出堡垒,并不能分出堡垒机.这样导致的问题是很多时候检索并不准确. 经过对比测试,发现nlpir进行分词效果更好.但是n ...
- Pycharm,Python 安装OpenCV and CV2 时,报错,教你如何正确安装。
Collecting cv2 Could not find a version that satisfies the requirement cv2 (from versions: ) No matc ...
- 论文笔记:Deeper and Wider Siamese Networks for Real-Time Visual Tracking
Deeper and Wider Siamese Networks for Real-Time Visual TrackingUpdated on 2019-04-01 16:10:37 Paper ...
- 【BUAA-OO】第二单元作业总结
第二单元作业总结 ——电梯恐惧症患者的极限自救 一. 第一次作业程序分析 1. 设计策略简略分析 线程:主线程.输入线程和电梯线程,另有一个持有请求队列的调度器,一个对输入进行处理的Req ...
- 6.4 SpringData JPA的使用
引言:该文档是参考尚硅谷的关于springboot教学视屏后整理而来.当然后面还加入了一些自己从网上收集整理而来的案例! 一.SpringData JPA初步使用 1. springdata简介 2. ...
- MAVEN中的Scope
Dependency Scope 在POM 4中,<dependency>中还引入了<scope>,它主要管理依赖的部署.目前<scope>可以使用6个值: *im ...
- jmeter系列-如何实现像loadrunner一样,多个并发用户先通过登录初始化,然后做并发的接口性能压测
自动转开发后,就很少关注性能测试方面的东西,最近在帮朋友做一个性能压测,由于朋友那边的公司比较小,环境比较简单,而且是对http服务进行的压测,所以最终 选用了jmeter来实现这个压测. 如下就是我 ...
- Java并发编程的艺术· 笔记(1)
目录 1.volatile的原理 2.Synchonized 3.无锁-偏向锁-轻量级锁-重量级锁 4.Java实现原子操作 1.volatile的原理 如何保持可见性: 1)将当前处理器缓存行的数据 ...
- android ------ AAPT2 error: check logs for details解决方法
AAPT 是全称是 Android Asset Packaging Tool,它是构建 App,甚至是构建 Android 系统都必不可少的一个工具.它的作用是将所有资源文件压缩打包到Android ...
- linux所有命令不能用显示-bash: ls: command not found
所有的命令都显示找不到了,原因是修改了/etc/profile造成的 解决方法 1.修正属性文件中的错误 /usr/bin/vi /etc/profile 2.生效属性文件 source /etc/p ...