1.认识TypeScript
编程语言分为动态类型语言如JavaScript和静态类型语言如Java。
动态类型语言没有编译阶段,而js本身具有非常大的灵活性,比如它没有类型约束,一个变量可能初始化为字符串,但也可以被赋值为数字,这使得我们用js编程时常常出现意外的错误或者隐患,从而导致运行时错误。
而静态类型语言在编译阶段就能确定每个变量的类型,能够发现大部分的错误。TypeScript就属于静态类型语言。
TypeScript是可扩展的JavaScript。兼容js,具有es6-es10的语法支持,能够兼容各种浏览器,使用ts能够减少代码错误,能够使程序更容易理解和维护,其代码补全、接口提示等功能能够提高我们的开发效率。
下面为大家介绍一些TypeScript的基础和常用语法。
2.安装TypeScript
// 安装
npm install -g typescript
// 编译
// 如果代码有错误,会在编译的时候报错
// 编译完成后会生成一个编译好的hello.js文件
tsc hello.ts
// 运行
node hello.js
复制代码
3.常用数据类型
以下介绍一些常用的数据类型
1.布尔值
let isDone:boolean = false
// 注意Boolean是js中的构造函数,
// 使用new Boolean()创造的不是布尔值,而是一个Boolean对象
let createdByNewBoolean: Boolean = new Boolean(1);
let createdByNewBoolean: boolean = new Boolean(1);
// Type 'Boolean' is not assignable to type 'boolean'.
//直接调用 Boolean 也可以返回一个 boolean 类型
let createdByBoolean: boolean = Boolean(1);
复制代码
2.数值
let age:number = 10
复制代码
3.字符串
let firstName:string = 'Tom'
复制代码
4.空值
ts中用void表示没有任何返回值的函数
function alert():void{
alert('hhhaaa')
}
复制代码
5.Null和Undefined
ts中,undefined 和 null 是所有类型的子类型。也就是说 undefined 类型的变量,可以赋值给 number 类型的变量
// 这样不会报错
let num: number = undefined;
复制代码
6.any
any表示任意类型,可以被改变,也可以访问任意属性和方法,不会报错。常用any表示数组中允许出现任意类型值
变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型
let notSure:any = 4
notSure = 'may be a string'
let something //等价于 let something:any
something = 'seven'
something = 7
复制代码
7.数组
数组有两种表示方式,1是:类型+方括号, 2是数组泛型 Array<类型>
let arr:number[]=[1,2,3] //数字类型数组,不允许有其他类型值
let arr2: number[] = [1, '1', 2, 3, 5];
// Type 'string' is not assignable to type 'number'.
let arr3: number[] = [1, 2, 3, 5];
arr3.push('8');
// Argument of type '"8"' is not assignable to parameter of type 'number'
//数组泛型
let arr:Array<numbei> = [1, 2, 3]
复制代码
类数组:常用的类数组都有自己的接口定义,如 IArguments, NodeList, HTMLCollection 等
function sum() {
let args: IArguments = arguments;
}
复制代码
8.元组
let user:[string,number]=['Tom',20] //指定了数组的长度和类型
user[0].slice(1)
user[1].toFixed(2)
user.push('123') //只能push两种类型中的一种
复制代码
9.接口
ts中,使用接口来定义对象的类型,用于对(对象的形状)进行描述
interface Person { //接口一般首字母大写
name:string;
age:number;
address?:string;
// ?表示可选属性
readonly id:number;
// readonly表示只读属性,初始化对象后不可以重新赋值
[propName:string]:any;
// [propName: string]定义任意属性,
// 一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
}
// tom变量的形状要和接口Person保持一致,多一个属性都不行
let tom:Person = {
name:'Tom',
age:20,
id:898,
gender:'male'
}
复制代码
10.函数
1.函数声明
// 传参数值类型x和y,并返回数值类型的数据
function sum(x:number,y:number):number {
return x+y
}
// 输入多余的或少于要求的参数,是不可以的
// 可以用?表示可选参数,可选参数必须接在必需参数后面
function add(x:number,y:number,z?:number):number{
if(typeof z === 'number'){
return x+y+z
}else{
return x+y
}
// 允许给参数添加默认值
function build(first:string,last:string='hello'){
return first + last
}
let tom = build('Tom')
复制代码
2.函数表达式
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
};
// ts中 =>用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。
复制代码
3.用接口定义函数形状
interface ISum {
(x:number,y:number):number;
}
let add:ISum = function(x:number,y:number){
return x+y
}
复制代码
11.never
当一个函数永远也执行不完,如抛错,可以给函数指定never返回值
function throwError(message:string,errorCode:number):never{
throw {
message,
errorcode
}
} // 永远也无法执行到这一行
throwError('Not Found',404)
复制代码
4.类型推论
TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推论。
let name = 'seven' //等价于 let name:string = "seven'
name = 7 //报错
// 如果定义的时候没有赋值,不管之后有没有赋值,都会推论成any
let name; // 等价于 let name:any;
name = 'seven';
name = 7;
复制代码
5.联合类型
联合类型表示取值可以为多种类型中的一种, 用 | 分隔每个类型
let numberOrString:number | string
// 允许numberOrString的类型是number或string,但不能是其他类型
numberOrString = 'Seven'
numberOrString = 7
复制代码
当ts不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法
function getLength(something: string | number): number {
return something.length;
// 报错,因为length不是string和number的共有属性
}
复制代码
联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型:
let numberOrString: string | number;
numberOrString = 'seven'; // 推论出string类型
console.log(numberOrString.length); // 5
numberOrString = 7; // 推论出number类型
console.log(numberOrString.length); // 编译时报错
复制代码
6.类型断言
当ts不确定一个联合类型的变量到底是哪个类型时,可以手动指定一个值的类型,从而访问其特有的方法和属性,使用类型断言时要格外小心,注意避免运行时错误。
function getLength(input:string|number):number{
const str = input as string
if(str.length){
return str.length
}else{
const number = input as number
return number.toString().length
}
}
复制代码
7.内置对象
JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型.。TypeScript 核心库的定义文件中定义了所有浏览器环境需要用到的类型,并且是预置在 TypeScript中的
ECMAScript 标准提供的内置对象有:Boolean、Error、Date、RegExp 等
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) {
// ...
});
复制代码
8.类型别名
就是给类型起个新名字,使用 type 创建,常用于联合类型
type NameOrResolver = string | number;
const a:NameOrResolver = 2
复制代码
9.字符串字面量类型
用来约束取值只能是某几个字符串中的一个
type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
// do something
}
handleEvent(document.getElementById('hello'), 'scroll');
复制代码
10.枚举
用于取值被限定在一定范围内
enum Direction {Up, Left, Down, Right}
console.log(Direction.Up) // 0
// 枚举成员会被赋值为从0开始递增的数字
console.log(Direction[0]) // Up
// 也可以根据枚举值取到枚举名
//也可以给枚举成员手动赋值,未手动赋值的枚举项会接着上一个递增
enum Direction {Up=3, Left=0, Down, Right}
console.log(Direction.Down) // 1
复制代码
11.类
TypeScript除了实现了所有ES6中的类的功能以外,还添加了一些新的用法
1.修饰符和readonly
TypeScript 可以使用三种访问修饰符分别是 public、private 和 protected。
- public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
- private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
- protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
- 当构造函数修饰为 private 时,该类不允许被继承或者实例化
- 当构造函数修饰为 protected 时,该类只允许被继承
class Animal {
public name;
private age;
public constructor(name,age) {
this.name = name;
this.age = age;
}
}
let a = new Animal('Jack',28);
console.log(a.name); // Jack
// name被设置为public,可以直接访问实例的name属性
console.log(a.age) //报错
// age被设置为private,不可访问
复制代码
readonly:只读属性关键字,注意如果 readonly 和其他访问修饰符同时存在的话,需要写在其后面
修饰符和readonly还可以使用在构造函数参数中,等同于类中定义该属性同时给该属性赋值,使代码更简洁。
class Animal {
// public name: string;
public constructor(public name) {
// this.name = name;
}
}
复制代码
2.给类加上ts类型
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
sayHi(): string {
return `My name is ${this.name}`;
}
}
let a: Animal = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack
复制代码
3.类实现接口
一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口,用 implements 关键字来实现。这个特性大大提高了面向对象的灵活性
interface Alarm {
alert(): void;
}
interface Light {
lightOn(): void;
lightOff(): void;
}
class Door {
......
}
class SecurityDoor extends Door implements Alarm {
alert() {
console.log('SecurityDoor alert');
}
}
class Car implements Alarm,Light {
alert() {
console.log('Car alert');
},
lightOn() {
console.log('Car light on');
}
lightOff() {
console.log('Car light off');
}
}
复制代码
4.接口之间的继承
interface Alarm {
alert(): void;
}
interface LightableAlarm extends Alarm {
lightOn(): void;
lightOff(): void;
}
//LightableAlarm继承了Alarm,
//除了拥有 alert 方法之外,还拥有两个新方法 lightOn和lightOff
复制代码
12.泛型
泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型
1.基本用法
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
//在函数名后添加了<T>,其中T用来指代任意输入的类型,
//在后面的输入 value: T 和输出 Array<T> 中就可使用了
createArray<string>(3, 'x'); // ['x', 'x', 'x']
// 传入字符串value,输出字符串类型数组
createArray<number>(3, 2); // [2, 2, 2]
// 传入数值value,输出数值类型数组
//可以一次性定义多个类型参数,使用元组的形式
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
swap([7, 'seven']); // ['seven', 7]
复制代码
2.泛型约束
在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法,这时,我们可以用extends对泛型进行约束,只允许这个函数传入那些包含特定属性或方法的变量,这就是泛型约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
loggingIdentity(7) //报错
//如果调用loggingIdentity的时候,传入的arg不包含length,那么在编译阶段就会报错
复制代码
3.指定泛型参数的默认类型
当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用
function createArray<T=string>(length: number, value: T): Array<T> {
...
}
复制代码
4.泛型接口
使用含有泛型的接口来定义函数的形状
interface CreateArrayFunc<T> {
(length: number, value: T): Array<T>;
}
let createArray: CreateArrayFunc<any>;
createArray = function<T>(length: number, value: T): Array<T> {
...
}
createArray(3, 'x'); // ['x', 'x', 'x']
复制代码
注意,此时在使用泛型接口的时候,需要定义泛型的类型。