ts简介
什么是typescript
- GitHub:TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
- TypeScript:TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
- TypeScript是JavaScript的超集,它带有类型并编译出干净的JavaScript代码.
- TypeScript支持JavaScript的所有特性,并跟随ECMAScript的标准发展,因此支持ES6,ES7,ES8等语法标准
- 除了类型约束,TypeScript还增加了一些语法扩展,例如枚举类型,元组类型等
- TypeScript总是与ES标准保持同步甚至领先,最终编译成JavaScript代码,不存在兼容性问题,不需要依赖Babel等工具.
搭建TypeScript运行环境
使用ts-node库为TypeScript的运行提供运行环境,这样就可以通过Node.js命令直接执行TypeScript代码,无须手动编译成JavaScript代码,当然还可以通过webpack搭建TypeScript运行环境,这里我们是通过ts-node来测试的
TypeScript的数据类型
any类型
在某些情况下,我们难以确定变量的类型,且类型可以会发生变化,这时可以使用any类型,any类型具有以下特点:
- 可以对any类型的变量进行任何操作,包括获取不存在的属性和方法
- 可以为一个any类型的变量赋任意值,如数字或字符串的值
/**
* 数组工具类,从AS移值过来
*/
export class ArrayUtils {
/**
* 判断数据是否为空
*/
static isEmpty(value: Array<any>): boolean{
return value === undefined || value == null || value.length === 0;
}
/**
* 是否包含
*/
static contains(data: Array<any>, target: any): Boolean {
return !ArrayUtils.isEmpty(data) && data.indexOf(target) !== -1;
}
}
console.log(ArrayUtils.contains([1, 2, 3], 3))
unknown类型
unknown是TypeScript中比较特殊的一种数据类型,用于描述类型不确定的变量.
function foo(){return "abc"}
function bar(){return 123}
// 1.unknown类型:只能赋值给any和unknown
// 2.any类型:可以赋值给任意类型
let flag = true
let result: unknown // 可接收类型
if (flag){
result = foo() //接收string类型
}else{
result=bar() //接收number类型
}
console.log(result);
// 下面两个赋值会报错,因为unknown类型只能赋值给any和unknown类型
// let message: string = result
// let num: number = result
void类型
void通常用于指定一个函数没有返回值,因此其返回值类型为void,如果函数返回void类型,则可以将null或undefined赋值给该函数,即函数可以返回null或undefined.
/**
* 数组工具类,从AS移值过来
*/
export class ArrayUtils {
/**
* 将一个对象随机位置放在数组中
*/
static insertRandom(data: Array<any>, target: any): void {
var index = Math.floor(Math.random() * data.length);
data.splice(index, 0, target);
console.log(data)
}
}
ArrayUtils.insertRandom(["呵呵", "嘻嘻", 1], "你是mm还是gg")
never类型
never类型表示永远不会有返回值的类型
- 如果一个函数陷入死循环活着抛出一个异常,那么这个函数将不会有任何返回值
- 如果一个函数确实没有返回值,那么使用void类型活着其他类型作为返回值类型不适合,这时就可以使用never类型.
export {}
function loopFoo(): never { //never类型,说明该函数不会返回任何内容
while (true) {
console.log("123")
}
}
function handleMessage(message: number|string){
switch (typeof(message)){
case 'string':
console.log('foo');
break
case 'number':
console.log('bar');
break
default:
//当执行这里的代码时,将message赋值给never类型的check会报错
//这样就可以保证,当修改参数的类型后,一旦出现case没有处理到的情况,就会报错
//例如,参数增加对boolean类型的支持时,必须在case中编写对应的处理情况,否则报错
const check: never = message;
}
}
tuple类型
元组类型,即多个元组的组合,许多编程语法中有这种数据类型,例如Python和Swift等.
以下是元组和数组类型的区别:
- 数组中通常建议只存放相同类型的元素,不推荐存放不同类型的元素.
- 元组中每个元素都有自己独特的类型,对于通过索引值获取到的值,可以确定其对应的类型
function useState(state: any){
let currentState = state
const changeState = (newState: any) => {
currentState = newState
}
const tuple: [any, (newState: any) => void] = [currentState, changeState]
return tuple
}
const [counter, setCounter] = useState(10); //解构出来的counter, setCounter是有类型提示的
console.log(counter, setCounter);
export {}
TypeScript类型的补充
函数的参数和返回值
函数是javascript中非常重要的组成部分,TypeScript允许我们指定函数的参数和返回值的类型.
export {}
function sum(num1: number, num2: number) {
console.log(num1 + num2);
return num1 + num2;
}
sum(1, 2)
// 当调用sum函数,如果传入的参数类型或数量不正确,就会报错
// 为返回值加上类型注释(): number
function sum1(num1: number, num2: number): number{
console.log(num1 + num2);
return num1 + num2;
}
sum1(1, 2)
// 在typescript中,返回值的类型注解和变量的类型注解相似,通常不需要显式地指定返回类型
// typescript会根据函数内部的return语句推断函数的返回类型,不过,为了增加代码的可读性,有些第三方库会显式指定函数的返回类型.
对象类型
如果希望限定一个函数接收的参数类型为对象类型,可以用对象类型作为参数
// 为参数point指定对象类型 {x: number, y: number}
function printPoint(point: {x: number, y: number}){
console.log(point.x);
console.log(point.y);
}
printPoint({x: 200, y: 100})
// 这里我们使用一个对象{x: 200, y: 100}作为类型
// 可以向对象添加属性,并告知typescript该属性的类型.
// 属性之间可以使用,或;分隔,最后一个分隔符是可选的
// 每个属性的类型也是可选的,如果不指定,那么默认为any类型.
// 在对象类型中,我们可以通过在属性名后面添加(?)的方式来指定某些属性为可选属性
// 为参数point指定对象类型: {x: number, y: number, z?: number}
function printPoint1(point: {x: number, y: number, z?: number}){
console.log(point.x);
console.log(point.y);
console.log(point.z);
}
printPoint1({x: 123, y: 321})
printPoint1({x: 123, y:321, z:231})
export {}
联合类型
typescript的类型系统允许我们使用多种运算符,从现有类型中构建新类型
- 联合类型由两个或多个其他类型组成
- 表示该类型可以是这些类型中的任何一个值
- 联合类型中的每个类型被称为联合成员
比如我定义了一个接口LogType,LogType有一个key属性可以为number或string类型,并且这个key属性为可选属性
export interface LogType {
key?: number | string,
name?: string,
status?: 'start' | 'stop' | 'success' | 'failed' | 'error',
message?: string,
data?: string[],
}
类型别名
interface Plat {
id?: number;
platformId?: number;
name?: string;
shortName?: string;
domain?: string;
locale?: string;
whiteList?: string[];
main_version_id?: number;
xlsFix?: string;
operator_id?: number;
operatorId?: number;
operator_name?: string;
game_id?: number;
game_name?: string;
config_file_name?: string;
}
type PlatformSelectGroupType = { name?: string, key?: number, id?: number, platformList?: Plat[] }
let Platform: PlatformSelectGroupType = {}
console.log(typeof Platform)
export type ThemeType = 'filled' | 'outlined' | 'twoTone';
const fillTester = /-fill$/;
const outlineTester = /-o$/;
const twoToneTester = /-twotone$/;
export function getThemeFromTypeName(type: string): ThemeType | null {
let result: ThemeType | null = null;
if (fillTester.test(type)) {
result = 'filled';
} else if (outlineTester.test(type)) {
result = 'outlined';
} else if (twoToneTester.test(type)) {
result = 'twoTone';
}
return result;
}
console.log(getThemeFromTypeName('icon-o'))
分别使用类型别名申请自定义类型PlatformSelectGroupType和ThemeType
类型断言
类型断言as
有时TypeScript无法获取具体的类型信息,这时就需要用到类型断言,比较常见的话定义一个枚举类型,申明变量的时候使用as断言断言为这个枚举类型
export {}
type RowSelectionType = 'checkbox' | 'radio';
let type = "checkbox" as RowSelectionType;
console.log(type);
非空类型断言
在javascript中经常使用if语句进行非空判断,而在typescript中,除了if语句,还可以使用非空类型断言进行非空判断
/**
* 数组工具类,从AS移植过来
*/
export class ArrayUtils {
/**
* 比较两个数组的值是否一致
* 注意传入的数据需要带有id字段
* @param arr1 数组1
* @param arr2 数组2
*/
static checkArrayIsSame = (arr1: any[], arr2: any[]) => {
// 首先会判断两个数组的长度,长度不一致,那值也不一致
if (arr1?.length !== arr2?.length) {
return false;
}
// 根据每个值的id字段进行比较
for (let i = 0; i < arr1.length; i++) {
if (arr1[i].id !== arr2[i].id) {
return false;
}
}
return true;
}
}
console.log(ArrayUtils.checkArrayIsSame([1, 2, 3], [1, 2]));
上面的示例中我们使用了可选链,arr1?.length, arr2?.length相当于当arr1和arr2不为空时才会去比较它们的长度
!!操作符
!!操作符可以将一个其他类型的元素转换成boolean类型,类似于Boolean(变量)这种函数转换的方式.
比如需要对不同端设备进行适配
const ua = window.navigator.userAgent;
const iOS = !!ua.match(/iPhone/i);
const webkit = !!ua.match(/WebKit/i);
const iOSSafari = iOS && webkit && !ua.match(/CriOS/i);
ua获取 用户代理, iOS判断是否为iPhone设备,为iPhone则iOS为true,webkit 设备代理为Webkit则webkit为true,下面iOSSafari判断是否为 iOS 设备上的 Safari 浏览器,是的话则iOSSafari为true,后面就可以拿iOSSafari这个变量进行判断做适配动作
??操作符
??操作符是es11新增的空值合并操作符,用于判断一个值是否为null或undefined,具体来说,当左侧操作数为null或undefined时,返回右侧操作数,否则返回左侧操作数,该操作符可以简化代码,并提高代码的可读性
let message: string|null = 'Hello HarmonyOS'
// 1.以前的方式是使用三元运算符判空,赋默认值(会判断null, undefined, false为假)
const content1 = message ? message: "你好啊,李银河!";
// 2.使用||操作符判空,赋默认值(会判断null, undefined, false为假)
const content2 = message || "你好啊,李银河2!";
// 3.使用??操作符判空,则赋默认值(会判断null, undefined, false为假)
const content3 = message ?? "你好啊,李银河3!";
console.log(content3);
export {}
字面量类型
在typescript中,除了上述类型,还可以使用字面量类型
// "Hello World"也可作为一种类型,叫做字面量类型
let message: "Hello World" = "Hello World"
// message = "coder" 报错不能将类型“"coder"”分配给类型“"Hello World"”
// 要体现字面量类型的意义,必须结合联合类型
type Alignment = 'left' | 'right' | 'center'
let align: Alignment = 'left' // ok
// let align2: Alignment = 'bottom' // 报错 不能将类型“"bottom"”分配给类型“Alignment”。
类型缩小
在typescript中,缩小类型的过程被称为类型缩小,我们可以使用类似typeof padding === "number" 的条件语句改变typescript的执行路径,在特定的执行路径中,可以缩小变量的类型,使其比声明时更为精准
常见的类型保护如下:
- typeof: 如typeof padding === "number"
- 平等缩小如 ===, !=, switch
- instanceof: 如d instanceof Date
- in: 如'name' in {name: "coder"}
typeof
javascript支持typeof运算符,可以使用该运算符来检查值的类型,在typescript中可以通过检查值的类型来缩小不同分支中的类型,这种检查值的类型称为类型保护
export class Utils {
/**
* 判断属性类型是否为方法
* @param obj 方法属性
*/
static isFunction(obj: any): obj is Function {
// typeof用于判断基本数据类型
return typeof obj === "function";
}
/**
* 判断属性类型是否为对象
* @param obj
*/
static isObject(obj: any) {
return Object.prototype.toString.call(obj) == "[object, Object]";
}
/**
* 判断变量是否为空
* @param value
*/
static isEmpty(value: any): boolean {
return value === undefined || value === null;
}
/**
* 判断变量是否有值
* @param value
*/
static hasValue(value: any): boolean {
return !Utils.isEmpty(value);
}
/**
* 判断属性类型是否为数值型
* @param value
*/
static isNumber(value: number): value is number {
return Utils.hasValue(value) && typeof value === 'number'
}
/**
* 判断属性类型是否为逻辑型
* @param value
*/
static isBoolean(value: boolean): value is boolean {
return Utils.hasValue(value) && typeof value === 'boolean';
}
}
平等缩小
可以使用switch, === !== !=等运算符来表达相等性,进而实现类型缩小,axios请求工具封装代码示例
export class Utils {
static isString(value: string): value is string {
return Object.prototype.toString.call(value) === "[object String]";
}
}
import {createBrowserHistory} from 'history';
const history = createBrowserHistory();
// response处理
function handleFailedResponse(response) {
// 反构请求的状态信息
// status 状态码
// statusText 状态文本
const {status, statusText} = response;
switch (status) {
case 401:
// 清除本地存储
localStorage.removeItem('token');
response.data.msg = 401;
history.push('/', {from: history.location});
break;
default:
if (!Utils.isString(response.data)) {
response.data.msg = "请求失败: " + status + " " + statusText;
}
break;
}
return Promise.reject(response);
}
次处使用case对响应状态码进行判断,如果是401的话则清除缓存,reponse data msg属性等于401 返回主页, 否则 reponse data msg属性等于其他状态码加状态文本
instanceof
javascript中有一个instanceof运算符,用于检查一个值是否为另外一个值的实例
export {}
class Student {
studying() {}
}
class Teacher {
teaching() {}
}
function work(p: Student | Teacher) {
// 判断p是否为Student类型的实例还是为Teacher类型的实例
if (p instanceof Student) {
p.studying()
}else{
p.teaching()
}
}
const stu = new Student()
work(stu)
可以看到,在work函数中通过判断变量p是否为Student类型的实例,将联合类型的p缩小为更具体的Student类型
in
javascript中有一个in运算符,用于判断对象是否具体指定名称的属性,如果指定属性存在于该对象或其他原型链中,那么in运算符将返回true,示例我之前写的一个获取机器可部署数量的方法发起getHostList请求,拿到response,判断当response返回对象有data属性,并且data.data属性值为一个数组才会执行下面的统计操作