StepByStep前端科普系列(007)-管中窥豹之typescript

100 阅读6分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

编程实际上就是对数据进行操作和加工的过程。类型系统能辅助我们对数据进行更为准确的操作。TypeScript 的核心就在于其提供一套类型系统,让我们对数据类型有所约束。约束有时候很简单,有时候很抽象。

TS 支持的类型如下:boolean,number,string,[],Tuple,enum,any,void,null,undefined,never,Object。 TS 中更复杂的数据结构其实都是针对上述类型的组合

以上, TypeScript - 一种思维方式

0. 官方文档以及综述

typescript 在线

www.tslang.cn/docs/handbo…

devblogs.microsoft.com/typescript/

github.com/microsoft/T…

TypeScript 概述 - Training | Microsoft Learn

进阶:使用 TypeScript 来重构 axios

JavaScript 是解释型语言,没有编译阶段,所以它是动态类型的语言。动态类型的语言是指在运行时才会进行类型检查的语言,这种语言的类型错误往往会导致运行时错误。

TypeScript 在运行前需要先编译为 JavaScript,而在编译阶段就会进行类型检查,所以 TypeScript 是静态类型。静态类型是指编译阶段就能确定每个变量的类型,这种语言的类型错误往往会导致语法错误。

1. 安装-编译

```
npm install -g typescript   // 全局安装

tsc hello.ts  // 编译

node  hello.js  // 执行
```

VSCode安装插件Code Runner,右键Run Code 即可

2. 字符串

let myName: string = 'Tom';
let myAge: number = 25;

// 模板字符串
let sentence: string = `Hello, my name is ${myName}.
I'll be ${myAge + 1} years old next month.`;

其中 ` 用来定义 ES6 中的模板字符串,${expr} 用来在模板字符串中嵌入表达式

编译后:

var myName = 'Tom';
var myAge = 25;
// 模板字符串
var sentence = "Hello, my name is " + myName + ".
I'll be " + (myAge + 1) + " years old next month.";

3. 接口

我们定义了一个接口 Person,接着定义了一个变量 tom,(tom对象),它的类型是 Person。这样,我们就约束了 tom 的形状必须和接口 Person 一致,即定义的变量比接口少一些属性或多一些属性都是不允许的。

interface Person {
    name: string;
    age: number;
}

let tom: Person = {
    name: 'Tom',
    age: 25
};

可选属性,age?:number;  

tom(tom对象)可以不定义该属性

可选属性的含义是该属性可以不存在

任意属性,[propName: string]: any;   (任意属性,任意取个名字的属性)

使用 [propName: string] 定义了任意属性取 string 类型的值

任意属性的类型为string时,那么确定属性和可选属性的类型都必须为它的类型的子集。此时,接口中其它属性必须也是string类型。

使用:gender:'male'   接口中无gender属性, 一个接口中只能定义一个任意属性。

如果接口中有多个类型的属性,则可以在任意属性中使用联合类型 [propName: string]: string | number; // 联合类型(Union Types)表示取值可以为多种类型中的一种

只读属性   readonly id: number;

对象初始化后,该属性不能二次赋值

4. 数组

// 类型 + 方括号  表示数组
let fibonacci: number[] = [1,1,2,3,5];
// 泛型 表示数组
let fibonacci: Array<number> = [1,1,2,3,5];

// 接口表示数组
interface NumberArray {
    [index:number]:number;
}
let fionacci:NumberArray = [1,1,2,3,5];

// 类数组
function sum(){
    let args:{
        [index:number]:number;
        length:number;
        callee:Function;
    } = arguments;
}

function sum(){
    let args:IArguments = arguments; // 其中 IArguments 是 TypeScript 中定义好了的类型
}

// any 在数组中的应用    用 any 表示数组中允许出现任意类型
let list: any[] = ['xiaoming',25,{websit:'www.xiaoming.com'}];

5. 函数

// javascript中两种定义函数的方式

// 方式一  函数声明
function sum(x,y){
    return x + y;
}

// 方式二  函数表达式
let mySum =  fuction(x,y){
    return x + y;
} ;  // ;

一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到

函数声明

function sum(x:number,y:number):number{
    return x + y;
}

函数表达式

let mySum  :  (x:number,y:number) => number    =    
    function (x:number,y:number) : number {
        return x + y;
};

TypeScript 中的 => 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。

(x:number,y:number) => number

用接口定义函数的形状

我们也可以使用接口的方式来定义一个函数需要符合的形状

interface SearchFunc {
    (source:string,subString:string):boolean;
}

let mySearch: SearchFunc;
mySearch = function(source:string,substring:string){
    return source.serarch(subString) !== -1;
}

函数参数

// 可选参数    param?:string     可选参数后面不允许再出现必需参数
function buildName(firstName: string, lastName?: string)

// 参数默认值   TypeScript会将添加默认值的参数识别为可选参数
param:string = 'defaultValue'

剩余参数   ...rest 获取函数中的剩余参数

6. 内置对象

ECMAScript标准提供的内置对象有:Boolean、Error、Date、RegExp等,我们可以在TypeScript中将变量定义为这些类型。

let b:Boolean =  new Boolean(1);
let e:Error = new Error('Error occurred');
let d:Date =  new Date();
let r:RegExp = /[a-z]/;

DOM和BOM提供的内置对象有:Document、HTMLElement、Event、NodeList等

let body:HTMLElement = document.body;
let allDiv:NodeList =  document.querySelectorAll('div');
document.addEventListener('click',function(e:MouseEvent){
    // TODO
});

7. 类型别名

用来给一个类型起一个新名字。类型别名常用于联合类型。

type Name = string;
type NameResolver = ()=>string;
type NameOrResolver =  Name | NameResolver;
function getName(n:NameOrResolver):Name{
    if (typeof n === 'string'){
        return n;
    } else {
        return n();
    }
}

字符串字面量类型

用来约束取值只能是某几个字符串中的一个

type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
    // do something
}

handleEvent(document.getElementById('hello'), 'scroll');  // 没问题
handleEvent(document.getElementById('world'), 'dblclick'); // 报错,event 不能为 'dblclick'

// index.ts(7,47): error TS2345: Argument of type '"dblclick"' is not assignable to parameter of type 'EventNames'.

这个例子中,我们使用type定义了一个字符串字面量类型 EventNames,它只能取三种字符串中的一种。注意:类型别名与字符串字面量类型都是使用type进行定义。

8. 元组 Tuple

数组合并相同类型的对象,元组合并不同类型的对象。元组起源于函数编程语言。

// 定义一对值分别为 string 和 number的元组
let tom: [string,number] = ['Tom',25];

// 赋值或访问
let tom:[string,number];
tom[0] = 'Tom';
tom[1] = 25;

tom[0].slice(1);
tom[1].toFixed(2);

9. 枚举 enum

enum Days {Sun,Mon,Tue,Wed,Thu,Fri,Sat};
// 枚举成员会被赋值为从0开始递增的数字,同时也会对枚举值到枚举名进行反向映射
console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true

console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
console.log(Days[6] === "Sat"); // true

// 手动赋值
enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};

console.log(Days["Sun"] === 7); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true
// 未手动赋值的枚举项会接着上一个枚举项递增。

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情