TypeScript技术学习
TypeScript技术学习
TypeScript是微软出品的语言,是js的超集,添加了类型,接口等特性,使用tsc编译器可以将ts编译成js,实际浏览器和服务器上的仍然是js
特性
- ts会做静态类型检查,编译的时候会报错,但是依然会生成编译文件,有配置文件可以修改,让ts在报错情况下不生成js
数据类型
js中数据类型分为原始数据类型(布尔,数值,字符串,null,undefined,Symbol)和对象类型()
原始类型在ts中的应用
-
数值 ,
let test:number=123 -
布尔,
let test:boolean=true -
字符串,
let test:string='xxxxxx' -
Null,
let test:null=null -
Undefined ,
let test:undefined=null注意Null和undefined是所以类型的子类型,也就是其他类型可以被赋值为undefined或者null
任意值
可以使用Any声明任意值,可以任意赋值以及调用属性而不会报错
类型推论
声明并赋值时,没有指定类型的变量会根据赋值做类型推断,没有赋值的声明会被认为是any
联合类型
使用let test: string|number可以声明联合类型,可以将不同类型的值赋予给联合类型,但是联合类型只能掉用两种类型共有的属性和方法。
交叉类型
使用 let test: A & B 可以声明交叉类型,交叉类型是将多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。
对象的类型-接口
一般使用
interface Person {
name:string;
age:number;
};
let tom :Person={
name:'xxx',
age:19
}
ts的接口可以定义对象属性,如上定义的接口,在被继承时不能新增属性,也不能减少属性。
可选属性
interface Person{
name:string;
age:number;
six?:string
}
如上定义的接口,six属性可空
任意类型属性
interface Perons{
name:string;
age:number;
six?:string;
[propName:string]:string | number;
}
如上定义的接口,可以使用任意属性。需要注意,任意属性的可选类型需要包含已定义属性的类型
只读属性
interface Perons{
readonly name:string;
age:number;
six?:string;
[propName:string]:string | number;
}
如上定义的接口,属性name为只读属性,不可被重新赋值以及修改。
数组类型
一般使用
let test:number[]=[1,2,3,4,5]
给数组加入任意不符合类型定义的值将会报错
数组泛型
let test:Array<number>=[1,2,3,4,5]
函数类型
函数声明
function test (x:number,y:number):number{
return x+y;
}
函数表达式
仅对等式右边进行了类型声明,左边使用的实际上是类型推断
let test=function(x:number,y:number):number{
return x+y;
}
或,对等式两边都进行了类型声明
let test:(x:number,y:number)=>number=function(x:number,y:number):number{
return x+y;
}
使用接口定义
interface ITest{
(x:number,y:number):number;
}
let test:ITest;
test=function(x:number,y:number){
return x+y;
}
可选参数
我们使用?表示表示参数可选,但是可选参数后不能有必选参数
function test(x:number,y:number,z?:number):number{
if(z!=undefined){
return x+y+z;
}
return x+y
}
参数默认值
当使用默认值时,不受可选参数后不能有必选参数的限制
function test(x:number,y:number,z:number=1)
剩余参数
使用...rest的方式获取剩余参数
function test(x:number,...items:any[])
重载
Ts 会优先匹配前面的定义,因此应该将最精准匹配的放在最前面
function test(x:number):number;
function test(x:string):string;
function test(x:number | string): number| string{
if(typeof x=='string'){
return 'xxx';
}
return 0;
}
类型断言
类型断言可以手动指定一个值的类型
值 as 类型
类型断言的用途
- 将联合类型断言为其中一种类型,从而可以访问这个类型特有的属性。但是要注意这种做法可能会在运行时报错。
- 将父类型断言为具体的字类型。
- 将变量断言成
any从而可以访问任意属性而不报错,前提是你必须确定该对象上存在这个属性 - 将
any断言成具体的类型
类型断言的限制
- 联合类型可以被断言成具体类型
- 父类型可以被断言成具体的子类型
- 任何类型可以被断言成
any any可以被断言成人意类型
typescript是结构类型系统,类型之间的对比只会比较他们最终的结构,而忽略他们定义时的关系。
interface Animal{
name:string
}
interface Cat{
name:string;
run():void;
}
let tom:Cat={
name:'tom',
run:()=>{
console.log('run');
}
}
let animal:Animal=tom;
因为Animal和Cat项目兼容,所以可以使用实现了Cat接口的数据对象给声明为Animal的对象赋值,实际上,Animal和Cat与下面的实现相同
interface Animal{
name:string
}
interface Cat extends Animal{
run():void;
}
当Animal兼容Cat时,他们就可以互相之间进行类型断言。
双重断言
foo as any as other
将任意类型断言成any再将any断言成其他类型,这在ts编译阶段通常不会报错,但是这种做法其实跳过了类型,需要谨慎使用
类型断言和类型转换
类型断言只是用于TypeScript编译阶段,实际并不会影响对象的类型,在编译成js时类型断言语句会被删除,类型转换需要使用类型转换语句。
声明文件
当使用第三方库时,我们需要引用他的声明文件,才能获得相应的代码补全,接口提示等功能。
声明文件必需以 .d.ts 为后缀。
书写声明文件
declare var声明全局变量declare functon声明全局方法declare class声明全局类declare enum声明全局枚举类型declare namespace声明全局对象interface 和type声明全局类型
EMCAScript内置对象
EMCAScript标准的内置对象
Boolean、Error、Date、RegExp 等。
更多的内置对象,可以查看 MDN 的文档。
而他们的定义文件,则在 TypeScript 核心库的定义文件中。
DOM和BOM内置对象
Document、HTMLElement、Event、NodeList 等。
常用
let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', function(e: MouseEvent) {
// Do something
});
类型别名
类型别名用来给一个类型取一个新名字
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
}
元组
数组合并来相同类型的对象,而元组合并了不同类型的对象。
let tom:[number,string]=[1,'xxx']
越界的元素
当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型
let tom: [string, number];
tom = ['Tom', 25];
tom.push('male');
tom.push(true);//编译报错
枚举
简单的枚举定义
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 = 3, Mon = 1, Tue, Wed, Thu, Fri, Sat};
console.log(Days["Sun"] === 3); // true
console.log(Days["Wed"] === 3); // true
console.log(Days[3] === "Sun"); // false
console.log(Days[3] === "Wed"); // true
TypeScript不会检查手动赋值到覆盖问题,所以需要格外注意。
手动赋值的枚举项可以不是数字
enum Days {Sun = 7, Mon, Tue, Wed, Thu, Fri, Sat = <any>"S"};
手动枚举可以赋值为负数或者小数,后续未手动赋值的项目依然会以1为步长递增
enum Days {Sun = 7, Mon = 1.5, Tue, Wed, Thu, Fri, Sat};
console.log(Days["Sun"] === 7); // true
console.log(Days["Mon"] === 1.5); // true
console.log(Days["Tue"] === 2.5); // true
console.log(Days["Sat"] === 6.5); // true
常数项和计算所得项
枚举项有两种类型,常数项和计算所得项
前面列举的都是常数项,计算所得项如下
enum Color {Red, Green, Blue = "blue".length};
如果在计算所得项后有未手动赋值的枚举项,将会因为无法得到初始值报错
enum Color {Red = "red".length, Green, Blue};
// index.ts(1,33): error TS1061: Enum member must have initializer.
// index.ts(1,40): error TS1061: Enum member must have initializer.
常数枚举
常数枚举是使用const enum 定义的枚举类型
const enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
常数枚举和普通枚举的区别是,它会在编译阶段删除,而且不能包括计算成员
外部枚举
外部枚举是使用delare enum定义的枚举类型
declare enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
外部枚举通常出现在声明语句中。
类
传统方法中,使用构造函数创建类,通过原型链实现继承。在ES6中,我们有了class。
用法与C#等面向对象语言一致。

浙公网安备 33010602011771号