TypeScript(一)

308 阅读8分钟

1、准备

// 安装
npm i typescript -g
// 版本
tsc -v

// 默认调试,-w表监听所有ts文件,编译为js文件,再通过node运行js文件
tsc -w index.ts
node index.js

// 生成tsconfig.json
tsc --init

nodejs 环境执行ts

npm i ts-node -g
npm i @types/node -D

ts-node index.ts

2、基础类型

基础类型:Boolean、Number、String、null、undefined、Symbol、BigInt

Ⅰ. 字符串类型

let str:string = 'Avido';
let str2:string = `hey ${str}`; // 模板字符串

Ⅱ. 数字类型

NaN 和 Infinity都属于number类型。

let num_nan:number = NaN;
let num_infinity:number = Infinity; 
let num:number = 1008611;
let decimal:number = 6; // 十进制
let hex:number = 0xf00d; // 十六进制
let binary:number = 0b1010; // 二进制
let octal:number = 0o744; // 八进制

Ⅲ. 布尔类型

使用构造函数Boolean创造的对象不是布尔值。

let createBoolean:boolean = new Boolean(); // 报错,new Boolean()返回对象

// a. 直接使用布尔值
let b1:boolean = true;
// b. 通过函数返回布尔值
let b2:boolean = Boolean(1);

Ⅳ. 空值类型

void: 没有返回值,常用于函数声明。

void可以定义undefined 和null类型。

function myFn():void {
    console.log('hey, ok!');
}

let v1:void = null;   // 严格模式下会报错
let v2:void = undefined;

void 和undefined 、null的区别:undefined、null是所有类型的子类型。

// 如下面报错:
let test:void = undefined;
let test2:string = "1";
let test3:null = null;
let test4:undefined = undefined;
test2 = test;   // void类型无法分给其他类型
test2 = test3;  // 严格模式下报错
test2 = test4;  // 严格模式下报错

注:关闭严格模式

tsc --init  生成tsconfig.json,将"strict" 的值设置为false

// 非严格模式下穿插赋值
let n:null = null;
let u:undefined = undefined;
// n = u;
// u = n;s

3、任意类型

any unknown

丢失类型检查。声明变量没有指定变量类型时默认为any。


Ⅰ. 类型,从上往下包含。如Object包括Boolean、Number、String。

Top Type 顶级类型 any unknown
Object
Boolean Number String
boolean number string
true 100 'abc'
never

let a: any = [];
a = 10010;
a = 'abcd';
a = Symbol(1);

Ⅱ. any与unknown的区别

a. unknown只能赋值给自身或者any

b. unknown无法读取任何属性、无法调用方法

c. unknown 比 any更加安全

// unknown类型只能作为父类型不能作为子类型
let a1:any = 1;
let un1:unknown = 5;
let au_num:number = 6;

a1 = un1;
un1 = a1;
au_num = a1;
// au_num = un1;  // 无法赋值给number类型

let un2:unknown = {
    name: 'ABC',
    fn: () => {
        console.log(111)
    }
}
let a2:any = {
    name: 'DEF',
    fn: () => {
        console.log(0o0);
    }
}
// unknown无法读取属性和调用方法
// console.log(un2.name);
// console.log(un2.fn());
console.log(a2.name);
console.log(a2.fn());
console.log(a2.age);

4、Object object {}

Ⅰ. Object

所有原始类型和对象类型最终都指向Object。

Object接口定义了Object.prototype原型对象上的属性

let OB1:Object = 123;
let OB2:Object = [];
let OB3:Object = {};
let OB4:Object = () => 2333;

Ⅱ. object

常用于泛型约束,代表非原始类型的一个类型。

只能支持引用类型。

// let ob1:object = 123; // number
// let ob2:object = '123'; // string
// let ob3:object = false; // boolean
let ob4:object = []; // array
let ob5:object = {}; // object
let ob6:object = () => 0; // fn

Ⅲ. {}

字面量模式,相当于new Object

let eo1: {} = 123;
let eo2: {} = '123';
let eo3: {} = [];
let eo4: {} = {name:'I'};
// {} 无法进行赋值操作
// eo4.age = 11;
// eo4.name = '1123';

5、接口和对象类型( interface )

定义对象的方式用关键字 interface

定义一种约束,声明的变量要符合对应的数据结构。

Ⅰ. 重名的interface声明,会重合

interface Axx{
    name: string,
    age: number
}

interface Axx{
    birthday: string
}

// 此时hey必须存在定义的三个属性,否则会报错
let hey: Axx = {
    name: 'hey',
    age: 24,
    birthday: '1999-12-20'
}

Ⅱ. 任意key

只对必填字段做强校验,使用索引签名

interface Bxx{
    name: string,
    age: number,
    [propName:string]: any
}

// 该对象必须存在name和age,其他可任意声明,不做校验
let hey2: Bxx = {
    name: 'hey2',
    age: 25,
    sign: 'tag',
    plus: 3.0
}

Ⅲ. ? readonly

可选变量 只读

readonly 一般用于不可修改的函数,或者id值只读

interface Cxx{
    name: string,
    age?: number, // age可选
    readonly id: number,
    readonly fn: () => boolean
}

let hey3: Cxx = {
    name: 'hey3',
    id: 111222,
    fn: () => { return false }
}

hey3.name = 'heyy3';
// 为只读属性,不可重新赋值
// hey3.id = 222333; 
// hey3.fn = () => { return true }

Ⅳ. 接口继承

声明的接口继承其他接口,在定义对象时,其他接口声明的属性也需要存在。

interface Dxx extends FXX,GXX{
    name: string,
    id: number
}

interface FXX{
    zzz: boolean
}
interface GXX{
    YYY: object
}

let hey4: Dxx = {
    name: 'hey4',
    id: 222333,
    zzz: true,
    YYY: []
}

Ⅴ. 定义函数类型

interface InFn{
    // 参数为name,string类型;返回一个数字数组
    (name: string): number[]
}

const fn: InFn = function(name: string) {
    return [1,2,3]
}

6、数组类型

Ⅰ. 定义数组普通类型

// a.number[] boolean[] string[]
// b. 泛型 Array<boolean/number/string>
let arr1:number[] = [1,2,3];
let arr2:boolean[] = [true,false];
let arr3:string[] = ['1','0'];
let arr4:Array<number> = [3,6,9];

// arr1.unshift('1') // 数字类型数组
arr1.unshift(4);
console.log(arr1)

Ⅱ. 定义对象数组

interface X{
    name: string,
    age?: number
}

let arr5:X[] = [
    { name: 'i',age: 3 }, 
    { name: 'e' }
]

Ⅲ. 定义多维数组

let arr6:number[][] = [[1],[2]];
let arr7:Array<Array<number>> = [[1],[2]];

Ⅳ. 包含多种数据类型的数组

let arr8: any[] = [1,'str',false];
let arr9: [number, string, boolean, {}] = [1,'str',false, {}];

Ⅴ. 函数参数

参数作为一个数组在函数中调用。

类数组不属于数组,没有数组方法,ts内置对象IArguments定义类数组

function aFn(...args: number[]):void {
    console.log(args,'args');
    console.log(arguments,'arguments');
    // let a:any[] = arguments; // 报错,伪数组不存在数组方法
    let a:IArguments = arguments;
}
aFn(1,2);

// arguments 作为IArguments类型声明的原理
interface IA {
    callee: Function,
    length: number,
    [index:number]: any
}
let fn_arguments: IA = {callee: () => {}, length: 888, 333:()=> {}}

7、函数扩展

Ⅰ. 普通函数/箭头函数定义参数类型和返回值

function add(a:number,b:number):number {
    return a+b;
}
console.log(add(1,2))

const add2 = (a:number,b:number):number => {
    return a+b;
}
console.log(add2(1,1))

Ⅱ. 函数设置参数默认值、设置可选参数

参数有默认值时,不可为可选参数

function add3(a:number = 10,b:number = 3):number {
    return a+b;
}
console.log(add3());

function add4(a?:number,b?:number):number {
    return (a ? a : 1) + (b ? b:1);
}
console.log(add4(4));

// 定义剩余参数
const fn_left = (arr: number[], ...items:any[]):any[] => {
    console.log(arr,items);
    return items;
}
let aa_left:number[] = [2,2,2];
fn_left(aa_left,'666',1008,false)

Ⅲ. 配合interface定义参数为对象类型的函数

interface User{
    name: string,
    age: number
}

function getUserInfo(user:User):User {
    return user
}
console.log(getUserInfo({name: 'user', age: 999}));

interface IN_ADD{
    (num1: number, num2: number) : number
}
const in_add:IN_ADD = (num1: number,num2: number): number =>{
    return num1 + num2
}
console.log(in_add(5,5),'in_add')

Ⅳ. 函数this类型

interface Aee  {
    ae_arr: number[],
    add: (num:number) => void
}

let aee: Aee = {
    ae_arr: [1,1,3,5],
    add (num:number) {
        this.ae_arr.push(num); //? this无法获取ae_arr,实际在项目中是可以获取的
    }
}
aee.add(8);
console.log(aee,'aee')

// ts可以定义this类型,且必须是第一个参数定义this的类型
interface Aee2 {
    ae_arr: number[],
    add: (this: Aee2, num: number) => void;
}

let aee2: Aee2 = {
    ae_arr: [2,3,3],
    add(this: Aee2,num: number) {
        this.ae_arr.push(num)
    }
}
aee2.add(6);
console.log(aee2,'aee2')

Ⅴ. 函数重载

通过函数是否有传参数、参数类型等,定义函数不同功能。

例如在一个函数实现增删改查:

let num_arr:number[] = [1,2,3];
function findNum(id:number):number[]  // 传指定值,做查询
function findNum():number[]           // 无参数,查询全部
function findNum(arr:number[]):number[] // 传数组,做新增
function findNum(ids?:number | number[]):number[] {
    if(typeof ids === 'number') {
        return num_arr.filter(v => v === ids)
    } 
    else if(Array.isArray(ids)) {
        num_arr.push(...ids)
        return num_arr
    }
    else {
        return num_arr
    }
}

console.log(findNum());
console.log(findNum(3));
console.log(findNum([7,8,9]))

8、联合类型 | 交叉类型 | 类型断言

Ⅰ. 联合类型

变量支持多种数据类型

let phone: string | number = '010-223344';
let phone2: string | number = 1008611;

let fn_getBool = function(type: number | boolean):boolean {
    return !!type; // 强转
}

console.log(fn_getBool(1));
console.log(fn_getBool(false));

Ⅱ. 交叉类型

多种类型的集合。定义的对象包含多种属性

interface Person {
    name: string,
    age: number
}
interface Man {
    sex: number
}

const getInfo = (man: Person & Man) : void => {
    console.log(man)
}

getInfo({
    name: 'Bepo',
    age: 2333,
    sex: 1
})

Ⅲ. 类型断言

值 as 类型 || <类型>值

类型断言只能欺骗ts编译器,无法避免运行时的错误

const getLength = (val: number | string) : void => {
    // console.log(val.length); // 报错,number无法获取length
    console.log((val as string).length);
    // console.log((val as number).toFixed(2))
}
getLength(3.1415926);
getLength('3.1415926')

interface A{
    get: string
}
interface B{
    set: string
}
const getA = (type:A|B):void => {
    console.log((<A>type).get)
}
getA({set: 'aaa'});
getA({get: 'bbb'});

Ⅳ, 临时断言

any临时断言: 在any类型上访问任何属性都是允许的

// 在window上挂属性或者方法
// any临时断言: 在any类型上访问任何属性都是允许的
// window.abc = 123; // 报错。window上不存在abc属性
(window as any).abc = 123;

Ⅴ. as const

const name1 = 'name1';
// name1 = '111' ; // 无法修改
let name2 = 'name2' as const;
// name2 = '222'; // 无法修改

const arr1_const = [10,20];
let arr2_const = [10,20] as const;
arr1_const.unshift(30);
// arr2_const.unshift(30); // 已经断言字面量为[10,20],无法修改

9、内置对象

Ⅰ.ECMA: Number Date RegExp Error XMLHttpRequest

let num_ecma:Number = new Number(1);
let date_ecma:Date = new Date();
let reg_ecma:RegExp = new RegExp(/\w/);
let err_ecma:Error = new Error('错误');
let xml_ecma:XMLHttpRequest = new XMLHttpRequest();

Ⅱ. DOM: querySelect MouseEvent

HTML(元素名称)Element HTMLElement as Element

let div1= document.querySelector('div');
let div2 = document.querySelector('header');
let div3 = document.querySelector('footer') as Element;

let div4:NodeList = document.querySelectorAll('div');
let div5:NodeListOf<HTMLDivElement | HTMLElement> = document.querySelectorAll('div footer');

Ⅲ. BOM: promise localStorage location cookie

let b_localStorage: Storage = localStorage;
let b_location: Location = location;
let b_promise: Promise<string> = new Promise((r) => r('str'));
b_promise.then(res => {
    console.log(res.length) // 已声明为resolve为string类型,故可调用string方法
})
let cookie: string = document.cookie;
代码雨
//index.html
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Avido</title>
    <style>
        * {
            padding: 0;
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
    <script src="./index.js"></script>
</body>
</html>
// index.ts
let canvas= document.getElementById("canvas") as HTMLCanvasElement;
let ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
canvas.width = screen.availWidth;
canvas.height = screen.availHeight;

let rainStr: string[] = "ZYXDASGDUHLE293Y0102".split("");
let rainArr = Array(Math.ceil(canvas.width / 10)).fill(0); 
// 创建数组,值为0,length为屏幕宽度/10
console.log(rainArr);

const rain = () => {
  ctx.fillStyle = "rgba(0,0,0,0.05)"; // 背景色
  ctx.fillRect(0, 0, canvas.width, canvas.height); //背景色铺满: x,y,width,height
  ctx.fillStyle = "#0f0";
  rainArr.forEach((item, index) => {
    ctx?.fillText(
      rainStr[Math.floor(Math.random() * rainStr.length)],
      index * 10,
      item + 10
    ); // 取数组随机数,在index*10,item+19的xy轴展示
    rainArr[index] = item > canvas.height || item > 8000*Math.random() ? 0 : item + 10;
    // console.log(rainArr[index]);
     // item值超过屏幕高度或者取随机值置为0,即文字的展示高度(y轴)
  });
};

setInterval(rain, 60)

// 运行
tsc -w
打开index.html