入门
类型检测,相比javascript,在TS中允许你为变量指定类型,有更多语法提示。
类型注解:变量后跟 :number,string
等数据类型,约定了什么类型,就只能给变量赋值该类型的值,否则,就会报错
使用
安装:npm install -g typescript
编译:tsc xxx.ts
热编译:tsc -w xxx.ts
初始化:tsc --init
数据类型
基本数据类型
布尔值
let isDone:boolean = false;
数字
let sun:number = 1;
字符串
let str:string = “string”;
let sentence: string = `Hello, my name is ${ name }.
数组
let arr: Array<number> = [1,2];//允许数组内有数值
let a: [string] = ['1']; // 只允许数组内有1个字符串
let a1: string[] = ['1','2'];//只允许数组内有字符串
let b: any[] = [1,'2', {name:1}];//允许数组内有任意值
Null undefined
默认情况下null和undefined是所有类型的子类型
然而,当你指定了--strictNullChecks
标记,null
和undefined
只能赋值给void
和它们各自。
TS新增类型
元组 Tuple
元组类型允许表示一个已知元素数量和类型的数组,
各元素的类型不必相同。
let x: [string, number]; // 数组有两个元素,类型为字符串,数字
x = ['hello', 10]; // OK
x = [10, 'hello']; // Error
//超出元组定义的值,只有类型允许的才可接受
//我们称其为联合类型
x[3] = 'world'; // OK, 字符串可以赋值给(string | number)类型
console.log(x[5].toString()); // OK, 'string' 和 'number' 都有 toString
x[6] = true; // Error, 布尔不是(string | number)类型
枚举 enum
枚举类型可以为一组数值赋予友好的名字。
enum Color { red,green=2,blue=4};
let arr:Color=Color;
console.log(arr);
//元素标号(下标)默认从0开始
//{0: 'red', 2: 'green', 4: 'blue', red: 0, green: 2, blue: 4}
// 你可以根据下标获取元素,也可以反之用值获取其标示
console.log(arr[2]); // green
console.log(arr['green']);//2
任意值 any
any代表它可以是任意类型,在不清楚变量的类型时可以使用。
let Any: any = 123;
Any = '123';
Any = false;
// 包含任意类型的数组
let Arr: <any> = [1,'2',true];
空值 void
void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是void
function fn(e): void {
console.log('没有返回值');
}
//只能为它赋予undefined和null
let v:void = null;
Never
never类型表示的是那些永不存在的值的类型(抛出错误)
never类型是任何类型的子类型,也可以赋值给任何类型;
然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。 即使any也不可以赋值给never。
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {
}
}
类型断言
相当于告诉编译器,
“相信我,我知道自己在干什么”
“你不要帮我检查了, 相信我,它就是这个类型”
(通过原本不被通过的类型赋值)
函数
function 函数名(参数列表): 返回值类型 {
函数体 ...
[return 返回值;]
}
//可选参数 ?: 代表参数可不传。可选参数必须配置到参数的最后面
function fn(str:string,arr?:number):string {
return xxx;
}
TS class类
- 类的定义
class Person {
name: string;//属性,前面省略了public关键词
constructor(n: string) {//构造函数,实例化类的时候触发的方法
this.name = n;//使用this关键字为当前类的name属性赋值
}
run(): void {//方法
console.log(this.name+ "在跑步");
}
}
var p = new Person("张三");
p.run();
-
类的继承
类的继承:在 TypeScript 中要想实现继承使用 extends 关键字,只要一旦实现了继承关系,那么子类中便拥有了父类的属性和方法,而在执行方法过程中,首先从子类开始找,如果有,就使用,如果没有,就去父类中找。类的继承只能单向继承。
class Person {
name: string;//父类属性,前面省略了public关键词
constructor(n: string) {//构造函数,实例化父类的时候触发的方法
this.name = n;//使用this关键字为当前类的name属性赋值
}
run(): void {//父类方法
console.log(this.name + "在跑步");
}
}
//中国人这个类继承了人这个类
class Chinese extends Person {
age: number;//子类属性
constructor(n: string, a: number) {//构造函数,实例化子类的时候触发的方法
super(n);//使用super关键字调用父类中的构造方法
this.age = a;//使用this关键字为当前类的age属性赋值
}
speak(): void {//子类方法
super.run();//使用super关键字调用父类中的方法
console.log(this.name + "说中文");
}
}
var c = new Chinese("张三", 28);
c.speak();
- 修饰符
TypeScript 在class类里面定义属性的时候给我们提供了 三种修饰符
public
:公有类型,在当前类里面、子类、类外面都可以访问
protected
:保护类型,在当前类里面、子类里面可以访问,在类外部没法访问
private
:私有类型,在当前类里面可以访问,子类、类外部都没法访问
注意:如果属性不加修饰符,默认就是公有(public)。
- 静态属性
被静态修饰符修饰的属性就是静态属性,静态属性可以通过类名直接调用。
class Person {
name: string;//属性,前面省略了public关键词
static sex: string = "男";//被静态修饰符static修饰的属性
constructor(n: string) {//构造函数,实例化类的时候触发的方法
this.name = n;
}
run(): void {//方法
console.log(this.name+ "在跑步");
}
}
console.log(Person.sex);
- 静态方法
静态方法:被静态修饰符修饰的方法就是静态方法,静态方法可以通过类名直接调用,但是在静态方法内部,不能直接调用当前类的非静态属性、非静态方法。
class Person {
name: string;//属性,前面省略了public关键词
static sex: string = "男";//被静态修饰符static修饰的属性
constructor(n: string) {//构造函数,实例化类的时候触发的方法
this.name = n;
}
run(): void {//方法
console.log(this.name + "在跑步");
}
static print(): void {//被静态修饰符static修饰的方法
// console.log('姓名:' + this.name);//错误
console.log('性别:' + Person.sex);//正确
// this.run();//错误
}
}
Person.print();
- 抽象类
抽象类
TypeScript 中的抽象类:它是提供其他类继承的基类,不能直接被实例化。
用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类(也就是其子类)中实现,abstract抽象方法只能放在抽象类里面。
我们常常使用抽象类和抽象方法用来定义标准。
//动物抽象类,所有动物都会跑(假设),但是吃的东西不一样,所以把吃的方法定义成抽象方法
abstract class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
abstract eat(): any;//抽象方法不包含具体实现并且必须在派生类中实现
run() {
console.log(this.name + "会跑")
}
}
class Dog extends Animal {
constructor(name: string) {
super(name);
}
eat(): any {//抽象类的子类必须实现抽象类里面的抽象方法
console.log(this.name + "吃骨头");
}
}
var d: Dog = new Dog("小狼狗");
d.eat();
class Cat extends Animal {
constructor(name: string) {
super(name);
}
eat(): any {//抽象类的子类必须实现抽象类里面的抽象方法
console.log(this.name + "吃老鼠");
}
}
var c: Cat = new Cat("小花猫");
c.eat();
接口 interface
接口的用途就是:
对行为和动作进行规范和约束,规定这批类里必须提供某些方法,变量需为何种类型;
但是,接口中不能有方法体,只允许有方法定义。
属性类接口
//对传入对象的属性约束,以下这个是一个属性接口
interface FullName {
firstName: string;
secondName: string;
}
function printName(name: FullName) {
console.log(name.firstName + "--" + name.secondName);
}
//传入的参数必须包含firstName、secondName
var obj = {
age: 20,
firstName: '张',
secondName: '三'
};
printName(obj);//正确
// printName("1213");//错误
函数类型接口
//加密的函数类型接口
interface encrypt {
//约束传参及返回值
(key: string, value: string): string;
}
var md5: encrypt = function (key: string, value: string): string {
//模拟操作
return key + "----" + value;
}
console.log(md5("name", "zhangsan"));
类类型接口
interface Animal {
name: string;
eat(str: string): void;
}
//类接口需要 implements 关键字
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
eat() {
console.log(this.name + "吃大骨头");
}
}
var d = new Dog("小狼狗");
d.eat();
接口的继承
接口可以继承接口,接口之间和抽象类之间的继承都是单向单继承,但是实现接口的子类可以实现多个接口。
简单来说,对于类、抽象类、接口继承只能单继承,但接口却可以多实现。
//人这个接口
interface Person {
eat(): void;
}
//程序员接口
interface Programmer extends Person {
code(): void;
}
//小程序接口
interface Web {
app(): void;
}
//前端工程师
class WebProgrammer implements Person, Web {
public name: string;
constructor(name: string) {
this.name = name;
}
eat() {
console.log(this.name + "下班吃饭饭")
}
code() {
console.log(this.name + "上班敲代码");
}
app() {
console.log(this.name + "开发小程序");
}
}
var w = new WebProgrammer("小李");
w.eat();
w.code();
w.app();