类型
类型注解
-
: 类型
几种类型注解示例
类型 | 语法形式 |
---|---|
数字类型 | number |
布尔类型 | boolean |
字符串类型 | string |
符号类型 | symbol |
Void类型 | void |
Null类型 | null |
Undefined类型 | undefined |
Never类型 | never |
任意类型 | any |
数组类型 | T[] |
元组类型 | [T0, T1, ...] |
枚举类型 | enum T { ... } |
函数类型 | (p1: T1, p2: T2, ...) => T |
类类型 | T |
构造器类型 | new (p1: T1, p2: T2, ...) => R |
对象类型 | { ... } 或 interface T { ... } |
联合类型 | `T1 |
交叉类型 | T1 & T2 & ... |
简单类型
-
let a : string = "this is a" let b : number = 1 let c : boolean = true interface interF { // 属性间可以用,/;/换行符进行连接 name:string, sex?:string } let d : interF = { name:"ly" } function fun (param1 : string , param2 : number): void{ //TODO } let fn = fun
对象类型
-
// 声明一个值为对象字面量 let man = {name: 'joye', age: 30}; // 等价于 let man: {name: string; age: number} = {name: 'joye', age: 30};
接口类型
对象字面量
-
对象字面量在直接赋值的时候,编译器会检查字面量类型是否完全匹配,多一个或少一个属性都会报错。
-
interface Person { name: string; age: number; }; // 定义一个对象字面量male let male = { name: 'joye', age: 30, gender: 'male' }; // 正确,male包含Person接口的所有属性 let man: Person = male; //错误,直接赋值时会严格检查接口属性定义,多或少都不行 let man : Person = { name: 'joye', age: 30, gender: 'male' };
函数
-
let fn : (name: string, age: number)=>void //等价于 let fn: { (name: string, age: number): string; }
可索引值
-
数组
-
// 描述一个数组 interface StringArray { [index: number]: string; }
-
-
对象
-
// 描述一个对象 interface MyObject { [index: string]: string; }
-
-
类数组对象
-
由于JavaScript会将数字索引转换为字符串索引,数字索引和字符串索引的值的类型必须相等,或者数字索引的返回值必须是字符串索引返回值类型的子类型
-
// 正确 interface IndexObj { [x: number]: string; [x: string]: string; } // 错误,数字索引的值和字符串索引的值不匹配 // error TS2413: Numeric index type 'number' is not assignable to string index type 'string' interface IndexObj { [x: number]: number; [x: string]: string; }
-
类
-
// 定义一个类 class NewClass {} // 用接口来描述这个类类型 interface MyClass { new(): NewClass; } // 声明一个变量为描述这个类的接口类型并初始化 let myClass: MyClass = NewClass;
数组类型
- : []
函数类型
-
: (a?:string,b:symbol) => void
-
对参数和返回值进行显示类型注解
-
可选参数在必选参数之前
复合类型
-
交叉类型
-
T1 & T2 & ...
-
-
联合类型
-
T1 | T2 | ...
-
-
高级联合
-
值与类型 / 值与值 / 类型与类型 混合
-
let u: 99 | "A" | boolean | string ;
-
-
keyof 关键字
-
取出全部interface中定义的键名
-
interface student{ grade:string year:string } let stud_attr :keyof student //等价于 let stud_attr : "grade" | "year"
-
枚举类型
- 具有自增性,默认值为数字值
类类型
-
ES6
-
class people{ //实例属性 year = 10; coustructor(){ //实例属性也可以定义在构造函数中 this.mood = "happy" } sleep(){ //实例方法 } static peopleMethod(){ //类的静态方法 } } //类的静态属性 people.peopleOnlyAttr = "类"
-
-
TS
-
class people{ // age属性未显式添加修饰符,默认为public age: number; //实例属性 被保护,可以在派生类(继承父类的子类)被访问 protected year: number = 10; public sleep():void{ //实例方法 } //不能在声明它的类外部访问 private name: string; // 定义静态属性并初始化 static greeting: string = 'world'; constructor(theName: string) { this.name = theName; } }
-
抽象类、抽象方法
-
抽象类主要是用来被继承使用,抽象方法必须在派生类中必须被实现
-
抽象方法必须在抽象类中存在
-
抽象类可以没有抽象方法
-
// Animal是抽象类 abstract cLass Animal{ //抽象方法,没有方法体 abstract type( private typeOfAnimal:string):void } // 正确,抽象方法被实现 class Dog extends Animal { makeSound(): void{ // ... } }
-
-
类型推导
-
编译器自动推导出绝大部分未注解的类型
-
// 变量被自动推导为字符串类型 string let a = "this is a" // 等价于 let a : string = 'hello world'; // 返回值被自动推导为数字类型 number function isNum(param: number) { return param; } // 等价于 function isNum(param: number): number { return param; }
类型查询
-
//a 待注解方 //b 被推导方 a :typeof b
- 待注解方使用 typeof 去根据被推导方类型进行推导,从而给自己进行显式类型注解
-
// 函数fn为函数 function fn(){} // 通过类型查询声明d的类型为fn的类型 let d: typeof fn // 等价于 let d: () => void
泛型
- 函数名/类名/接口名 <T1,T2,T3...>
- 即定义时没有确定函数、类、接口的类型,在调用时在赋予具体的类型
泛型函数
function fun<T1>(param1:T2):void{
//TODO
}
let funMethod : string = fun <string> ("hello")
泛型类
class People<T1>{
name:T2
show<T3>():T2{
}
}
let man:People<string> = new People<string>()
a.name = "ly"
泛型接口
interface inter<T>{
attr:T
}
let a : inter<string> = "s"
let b : inter<number> = 10
function fun():void{}
let c : inter<typeof fun> = {
attr(){}
}
泛型约束
interface hasLength {
length:number.
}
//在未具体指定泛型(T)的实际类型时,如调用该类型的具体对象(如arg)的具体属性(length)
//需要使用 extends 泛型约束关键字 进行接口的约束
function getLength<T extends hasLength>(arg:T):number{
return arg.length
}
-
在未具体指定泛型(T)的实际类型时,如调用该类型的具体对象(如arg)的具体属性(length)
-
指定泛型默认值
interface MyType<T = string> { value: T; }
泛型数组
Array<T>
let arr: Array<number> = [1, 2, 3];
类型转换
类型别名
-
对原始类型的一个引用,完全等价于原类型
-
对原始类型的一个概括总结,提高类型注解的可读性
//联合类型别名 type stringOrNumber = string | number type sexs = "boy" | "girl" //泛型的实际类型别名 type types = typeAll<string,number> //泛型函数别名 type fun<T> = (data:T) => void
类型断言
-
在没有明确指定某个变量的类型时,后续要用到该变量的具体属性,需要对变量进行类型断言
-
为编译器进行类型解释
class Animal{} class Cat extends Animal{ sleep:(time:number)=>number{ return number } } let katty = new Cat() //编译报错,默认katty为Animal类型 katty.sleep(8) //应为katty进行类型断言 (katty as Cat).sleep(88) //或者 (<Cat>katty).sleep(88)
命名空间
命名空间
-
namespace产生一块新的作用域
-
命名空间内的变量外部无法访问
-
如需访问成员或者命名空间本身,都需要在声明时通过
export
进行导出namespace fruit{ export let apple = "red" let banana = "yellow" function eat(){ banana = "yellow,More" } } //正确 let apple : string = "error" //编译报错,banana为friut命名空间内的变量,未导出,不能进行访问 let banana : string = fruit.banana
对命名空间成员的访问,类似对象成员的访问,都是用点号运算符
.
空间拆分
- 命名空间拆分时要注意拆分后的命名空间成员依然无法互相访问
- 需要访问的空间或成员要增加export
空间嵌套
- 命名空间支持多层嵌套
空间别名
- 对命名空间进行重命名
- 通常在嵌套过深的命名空间中进行使用
namespace A{
export namespace B {
export namespace C {
export let msg = 'hello world';
}
}
}
import cc = A.B.C
import cmsg = A.B.C.msg
理解声明
内部声明
- 在使用ts的过程中的ts语法
外部声明
-
引用第三方库时TS无法识别,declare进行类型声明
-
不能在声名时初始化
declare let $ : (selector:string) => { html:()=>void }
三斜线指令和 .d.ts
- 三斜线指令
- 通常将TS声明文件进行引入
- 在编译阶段,被依赖文件 jquery.d.ts 将被包含进来,就像将被依赖文件的源码展开在依赖声明处一样
.d.ts
- 通常使用 .d.ts文件进行ts类型声明汇总
// jquery.d.ts 文件
declare let $: (selector: string) => {
html: (content: string) => void;
};
// main.ts 文件
// path 引用工程内文件
// types 引用 node_modules/@types 文件夹下的类型的依赖,不包含路径信息
/// <reference path="./jquery.d.ts" />
// 等价于将代码在三斜线指令处展开
declare let $: (selector: string) => {
html: (content: string) => void;
};
$('body').html('hello world');