本文总结一下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/10479 const 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"color: #ff0000">交叉类型
最典型的使用场景就是继承和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的作用
ype用来创建新的类型,也可以重命名(别名)已有的类型,建议使用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"htmlcode">
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"htmlcode">
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"htmlcode">
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 runtime
this.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.$eventBus
interface Vue {
$eventBus: Vue;
}
// 相当于在Vue.prototype.$eventBus
interface VueConstructor {
$eventBus: Vue;
}
}
总结
TypeScript声明还有很多高级的用法,目前我也没有用到那么多,在我纠结不会写声明的时候,我就会看看别人的声明文件时怎么写的。
注意:尽量不要把解构和声明写在一起,可读性极差。
class Node {
onNodeCheck(checkedKeys: any, { // 解构
checked, checkedNodes, node, event,
} : { // 声明
node: any;
[key: string]: any;
}
) {
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
DDR爱好者之家 Design By 杰米
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]