TypeScript 类型声明书写踩坑全解析
本文总结了TypeScript
类型声明的书写,很多时候写TypeScript
不是问题,写类型就特别纠结,我总结下,我在使用TypeScript
中遇到的问题。如果你遇到类型声明不会写的时候,多看看lodash
的声明,因为lodash
对数据进行各种变形操作,所以你能遇到的,都有参考示例。
基本类型
// 变量const num: number = 1;const str: string = 'str';const bool: boolean = true;const nulls: null = null;const undefine: undefined = undefined;const symbols: symbol = Symbol('symbal');const any: any = 'any types'; // typescript的any类型,相当于什么类型约束都没有
数组
// 数组: 推荐使用T[]这种写法const nums: number[] = [1, 2, 3, 4];// 不推荐:Array<T>泛型写法,因为在JSX中不兼容,所以为了统一都使用T[]这种类型const strs: Array<string> = ['s', 't', 'r'];const dates: Date[] = [new Date(), new Date()];
数组的concat
方法,返回类型为never[]
问题
// 数组concat方法的never问题// 提示: Type 'string' is not assignable to type 'never'.const arrNever: string[] = [].concat(['s']);// 主要问题是:[]数组,ts无法根据上下文判断数组内部元素的类型// @see https://github.com/Microsoft/TypeScript/issues/10479const fixArrNever: string[] = ([] as string[]).concat(['s']);
接口
接口是 TypeScript 的一个核心知识,它能合并众多类型声明至一个类型声明:
而且接口可以用来声明:函数,类,对象等数据类型
interface Name {first: string;second: string;
}let username: Name = {first: 'John',second: 'Doe'
};
any
、null
、undefined
、void
类型
// 特殊类型
const any: any = 'any types'; // typescript的any类型,相当于什么类型都没写
let nobody: any = 'nobody, but you';
nobody = 123;let nulls: number = null;
let bool: boolean = undefined;// void
function printUsername (name: string): void {console.log(name);
}
联合类型
联合类型在
option bags
模式场景非常实用,使用 **|**来做标记
function options(opts: {types?: string;tag: string | number;
}): void {}
交叉类型
最典型的使用场景就是继承和
mixin
,或者copy
等操作
// 交叉类型:如果以后遇到此种类型声明不会写,直接看Object.assign声明写法
function $extend<T, U>(first: T, second: U): T & U {return Object.assign(first, second); // 示意而已
}
元组 tuple
let nameNumber: [string, number];// Ok
nameNumber = ['Jenny', 221345];// Error
// nameNumber = ['Jenny', '221345'];let tuple: [string, number];
nameNumber = ['Jenny', 322134];const [usernameStr, uselessNum] = nameNumber;
type
的作用
type
用来创建新的类型,也可以重命名(别名)已有的类型,建议使用type
创建简单类型,无嵌套的或者一层嵌套的类型,其它复杂的类型都应该使用interface
, 结合implements
,extends
实现。
type StrOrNum = string | number;// 使用
let sample: StrOrNum;
sample = 123;
sample = '123';// 会检查类型
sample = true; // Error
实践中遇到的问题
第三方库没有提供声明d.ts
文件 (常见)
如果第三方库没有提供声明文件,第一时间去微软官方的仓库
https://github.com/borisyankov/DefinitelyTyped
查找,或者在npmjs.com
上搜索@types/
依赖的模块名大部分情况都可以找到。
手动添加声明文件
声明文件一般都是统一放置在types
文件夹下
// 例子: types/axios.d.ts
declare module 'axios'; // 这里的axios声明为any类型
全局变量
例如一些库直接把在
window
上添加的全局变量
// globals.d.ts
// 例子:jQuery,现实中jQuery是有.d.ts
declare const jQuery: any;
declare const $: typeof jQuery;
非JavaScript
资源
在前端工程中,import很多非js资源,例如:css, html, 图片,vue, 这种ts无法识别的资源时,就需要告诉ts,怎么识别这些导入的资源的类型。
// 看看vue怎么处理的:shims-vue.d.ts
declare module '*.vue' {import Vue from 'vue';export default Vue;
}// html
declare module '*.html';
// css
declare module '*.css';
强制类型转换
有时候遇到需要强制类型转换,尤其是对
联合类型
或者可选属性时。
// 第一种:使用<>括号
const convertArrType: string[] = <Array<string>>[].concat(['s']);// 第二种:使用as关键字
const fixArrNever: string[] = ([] as string[]).concat(['s']);
建议使用第二种,因为兼容JSX
,第一种官方也不推荐了,虽然它是合法的。
可选属性和默认属性
API中提供的参数很多都有默认值,或者属性可选,怎么书写呢?
class Socket {}
// 联合类型
export type SocketType = 'WebSocket' | 'SockJs';export interface SocketOptions {type: SocketType;protocols?: string | string[]; // 可选pingMessage: string | (() => string); // 联合类型,可以为string或者函数pongMessage: string | (() => string);
}// 默认值
export function eventHandler = (evt: CloseEvent | MessageEvent | Event,socket: Socket,type = 'WebSocket' // 默认值
) => any;
独立函数怎么声明类型
刚开始我也很纠结这个问题,我就是一个独立的函数,怎么声明类型呢?尤其是写事件处理函数
的API时。
class Socket {}
// 函数的声明方式
export type SocketEventHandler = (evt: CloseEvent | MessageEvent | Event,socket: Socket
) => any;const eventHandler: SocketEventHandler = (evt, socket) => {
}// 可选参数和rest参数
let baz = (x = 1) => {};
let foo = (x: number, y: number) => {};
let bar = (x?: number, y?: number) => {};
let bas = (...args: number[]) => {};
索引属性类型声明
JavaScript
中的对象都可以使用字符串索引直接取属性或者调用方法,TypeScript
中也有相应的类型声明方法。
type Hello = {hello: 'world';// key只是一个形式属性名(类似形参一样)[key: string]: string;
};const greeting: Hello = {hi: 'morning'
}console.log(greeting['hi']);
动态添加的属性声明
有的时候我们只声明了一个基本的类型结构,然后后续有扩展的情况 ,尤其时二次封装时的options
。
interface AxiosOptions {}type AjaxOptions = {axiosOptions: AxiosOptions;// 额外扩展的放入到单独的属性节点下extraOptions: {[prop: string]: any};
};type AjaxOptions1 = {axiosOptions?: AxiosOptions;// 不要这样写,因为axiosOptions拼写错误时,ts不会提示// 尽量把后续扩展的属性,移动到独立的属性节点下[prop: string]: any
};const ajaxOptions: AjaxOptions1 = {axiosOptions1: {}; // 本意是axiosOptions,但是ts不会提示
}
!
的使用
!
标识符告诉ts编译器,声明的变量没有问题,再运行期不会报错。
class BaseSelect extends Vue {options: string[]; // 这里会提示没有在constructor中初始化created() {this.options = ['inited']}
}class BaseSelect extends Vue {options!: string[]; // 使用 ! 告诉编译器,我知道自己在做什么created() {this.options = ['inited']}
}
this
的使用
对于独立使用的函数,可以声明指定的调用上下文
class Handler {info: string;// 声明指定的this上下文onClickBad(this: Handler, e: Event) {// oops, used this here. using this callback would crash at runtimethis.info = e.message;}
}
let h = new Handler();
uiElement.addClickListener(h.onClickBad); // error!
声明合并(扩展Vue
声明)
来看看使用场景,扩展vue
,在vue
上添加全局的属性。
// vue的声明在 vue/types/vue.d.ts
declare module 'vue/types/vue' {// 相当于Vue.$eventBusinterface Vue { $eventBus: Vue;}// 相当于在Vue.prototype.$eventBusinterface VueConstructor {$eventBus: Vue;}
}
忽略TypeScript的校验
Use // @ts-check to opt in to type checking for a single file.
Use // @ts-nocheck to opt out of type checking for a single file.
Use // @ts-ignore to opt out of type checking for a single line.
总结
TypeScript
声明还有很多高级的用法,目前我也没有用到那么多,在我纠结不会写声明的时候,我就会看看别人的声明文件时怎么写的。
注意:尽量不要把解构
和声明
写在一起,可读性极差。
class Node {onNodeCheck(checkedKeys: any, { // 解构checked, checkedNodes, node, event,} : { // 声明node: any;[key: string]: any;}) { }
}
150讲轻松搞定Python网络爬虫
Google开发专家带你学 AI:入门到实战(Keras/Tensorflow)(附源码)
参考:https://juejin.im/post/5d64c2bef265da03da24a410#heading-16
TypeScript 类型声明书写踩坑全解析相关推荐
- typescript索引类型_TypeScript类型声明书写详解
本文总结一下TypeScript类型声明的书写,很多时候写TypeScript不是问题,写类型就特别纠结,我总结下,我在使用TypeScript中遇到的问题.如果你遇到类型声明不会写的时候,多看看lo ...
- typescript的类型描述_TypeScript类型声明书写详解
本文总结一下TypeScript类型声明的书写,很多时候写TypeScript不是问题,写类型就特别纠结,我总结下,我在使用TypeScript中遇到的问题.如果你遇到类型声明不会写的时候,多看看lo ...
- vue在微信里面的兼容问题_详解Vue微信公众号开发踩坑全记录
本文介绍了Vue微信公众号开发踩坑全记录,分享给大家,也给自己留个笔记. 需求 微信授权登录(基于公众号的登录方案) 接入JS-SDK实现图片上传,分享等功能 现状及难点 采用的Vue框架,前后端分 ...
- Jetson Nano配置踩坑全记录
Jetson Nano配置踩坑全记录 Jetson Nano相关参数:JetPack 4.6,cuda 10.2, SD卡内存:512G 一.Jetson Nano系统镜像烧录 在Nvidia官网下载 ...
- 首次使用windows10安装DB2_10.5数据库踩坑全教程,附加问题解决目录思路汇总
新入职的IBM,需要安装IBM的数据库DB2,搞了两天踩坑全教程,下面是踩坑说明. DB2是IBM的数据库,官网说明是这个网址: IBM DocsIBM Documentation.https://w ...
- TypeScript 类型声明文件.d.ts
文章目录 一.TS 中的两种文件类型 二.类型声明文件的使用说明 1. 使用已有的类型声明文件 1.1 内置类型声明文件 1.2 第三方库类型声明文件 1.2.1 库自带声明文件 1.2.2 Defi ...
- HyperLPR 开源车牌识别系统搭建踩坑全记录
(介绍略) 一个开源的车牌识别系统. github地址:https://github.com/szad670401/HyperLPR 一.下载 git clone https://github.com ...
- linux ubuntu安装pytorch(深度学习环境搭建记录,无sudo权限)踩坑全记录
一些牢骚:深度学习没怎么学习几次,搭建环境已经把我搞秃了哈哈哈. 之前在网上找到的搭建环境的步骤,我没有root权限,很多操作都不行(比如运行.run文件,cuda 和cudnn的安装和修改也需要ro ...
- g++ linux 编译开栈_方舟编译器编译hello world踩坑全记录
闲来无事,看到方舟编译器完整开源,于是打算拿来试着编译一个东西来,接下来把踩过的一些坑记录一下. 参考文档 方舟编译器的官网是 OpenArkCompilerwww.openarkcompiler. ...
最新文章
- PyTorch 1.9发布,支持新API,可在边缘设备中执行
- oracle之Flash Recovery Area全面介绍
- “街坊”×××数字平台,昔日的思想,曾经的努力
- 信息学奥赛一本通(1055:判断闰年)
- 云计算学习(4-3)虚拟化技术-存储虚拟化
- [译][Tkinter 教程15] event 事件绑定
- springboot 启动 退出_springboot怎么停止掉服务器 我启动了springboot,但是我修改了程序,我怎么重启啊...
- 虚拟机实时迁移解决方案
- ABAP字符串的加密与解密
- pycharm添加conda虚拟环境
- js动态填充select
- ps只能选择html格式,怎么找不到ps“选择主体”功能?
- 正大市场监管总局、发改委、证监会联合提醒告诫部分铁矿石
- 使用O2OA二次开发搭建企业办公平台(十三)流程开发篇:报销审批流程表单开发...
- html设置行的水平对齐
- appuim+python+MUMU模拟器连接方法
- eplan 电箱布局_Eplan D布局步骤
- 【salesforce Admin必备】-想到啥写点啥
- java 使用 Amazon SES 发送电子邮件
- Nginx服务器部署
热门文章
- FAQ:Nacos报错:server is DOWN now, please try again later!
- style-loader和css-loader
- 树莓派 公网IP变动后 自动邮件通知 python
- 五、产业互联网价值——构建“双螺旋”产业结构,实现产业价值指数增长
- UE4模型轮廓描边及轮廓发光
- delphi文件操作
- oracle CONTAINS用法
- Elasticsearch 可视化界面工具
- CCNA 初学(第二课)
- 五角星具有“胜利”的含义。被很多国家的军队作为军官(尤其是高级军官)的军衔标志使用。也常常运用在旗帜上。我们的国旗上就有五角星。请你也画一个五角星吧。