TS开发环境搭建
- 安装node.js;
- 使用npm 全局安装 ts: npm i -g typescript ;
- 创建一个ts文件,编辑好之后,使用tsc命令对文件进行编译:tsc xxx.ts,会生成同名的js文件。
TS基本类型
- 类型声明:
- 通过类型声明指定TS中变量(形参、返回值)的类型,当为变量赋值时,TS编译器会自动检查变量是否符合定义的类型。
- 语法:
let 变量:类型;
let 变量:类型 = 值;
function fn(参数: 类型, 参数:类型): 返回值类型 {
...
}
- 自动类型判断:
- TS有自动判断类型的机制,定义变量时同时赋值而没有定义类型,那么TS会自动判断类型。
- 类型:
/*
1. 字面量: 限制变量的值就是其本身
*/
let a: 10;
a = 11; // 修改会报错,a只能是10
// 可以使用 | 来设置多个类型
let b: "male" | "female";
b = "male";
b = "female";
/*
2. any: 表示任意类型,相当于针对该变量关闭了ts的类型检测,不建议使用
*/
let d: any; // let d; 不指定类型,会默认为any类型
d = 10;
d = 'hello';
d = true;
/*
3. unknown 表示任意类型的值
*/
let e: unknown;
e = 10;
e = "abc";
e = true;
// unknown 和 any 的区别:unknown 相当于类型安全的any,不会影响其他变量的类型校验。
let s: string;
// d是any类型,并且d=true,但是s是string。
// 将d赋值给s是并没有报错,相当于不仅any类型的d关闭了类型校验,被赋值的s也被关闭了。
s = d;
// 将unknown类型的e赋值给s,会报错:不能将unknown类型赋值给string。
s = e;
// 类型断言,已经明确知道e是字符串,为了不让编译器报错,可以使用类型断言。
e = "abc";
s = e as string;
s = <string>e;
/*
4. void 和 never 一般用于指定函数的返回值
*/
// void 用来表示空,表示没有返回值或返回值为undefined、null
function fn(): void {
// 如果设置了返回值会报错
return 123
// 以下三种情况不会报错
return undefined
return null
return
}
// never 表示没有返回值
function fn1(): never {
// 如果设置了返回值会报错
return 123
// 以下三种情况不会报错
return undefined
return null
return
}
/*
5. object 表示一个js对象
*/
let f: object;
f = {};
f = function () {
};
// {} 用于指定对象中可以包含那些属性
// 语法: {属性1: 属性值, 属性2:属性值}
// 在属性名后面加 ? 代表属性是可选的
let g: {name: string, age?: number};
g = {name: '孙悟空', age: 18};
// 如果要表示name属性必须有,其他属性可有有无,则可以通过
// [propName: string]: any 表示任意类型的属性
let h: {name: string, [propNmae: string]: any};
h = {name: "猪八戒", age: 18, gender: "男"};
// 定义函数的结构,只能有a,b两个参数且为number,返回值也为number
let i: (a: number, b: number) => number;
i = function(n1, n2): number {
return n1 + n2
}
/*
6. array
*/
let l: (string|number)[]; // 数组中只能存在string 或 number
l = ["a", 1, ]
let m: Array<number|string>; // 数组中只能存在string 或 number
m = ["a", 1]
/*
7. tuple: 固定长度的数组
语法: [类型, 类型....]
*/
let n: [string, number];
n = ["a", 1];
n = ["a"]; // 个数不同也会会报错
n = [1, "a"]; // 顺序相反也会报错
/*
8. enum: 枚举
语法: [类型, 类型....]
*/
enum Gender{
Male = 0,
Female = 1
}
let o: {name: string, gender: Gender};
o = {
name: "孙悟空",
gender: Gender.Male
};
TS面向对象
类
通过类创建对象,类可以理解为对象的模型。
- 定义类:
class 类名 {
属性名: 类型;
constructor(参数: 类型) {
this.属性名 = 参数;
}
方法名() {
...
}
}
- 示例:
class Person {
// 实例属性
name: string;
// 类属性(静态属性,直接通过类访问,不需要创建对象)
static age: number;
// 只读属性,不能修改
readonly gender: string = "famale";
// 构造函数, 创建对象时传入name和age字段,创建不同的Person对象
constructor(name: string, age: number) {
// this就代表当前的实例对象,可以通过this设置当前实例的属性
this.name = name;
this.age = age;
}
// 定义方法
sayHello() {
console.log("hello")
}
}
let per = new Person("小红", 18);
console.log(per.name);
console.log(Person.age);
继承
- 继承语法: class 子类 extends 父类 { }
- 子类中添加属性需要重新构造函数时,需要调用父类的构造函数,使用super()。
class Animal {
public name: string;
public age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log("动物在叫。")
}
}
// Dog 通过 extends 关键字继承父类Animal
class Dog extends Animal {
gender: string;
constructor(name: string, age: number, gender: string) {
// 子类中添加属性需要重新构造函数时,需要调用父类的构造函数,使用super()
super(name, age);
this.gender = gender;
}
run() {
console.log("狗在叫。")
}
}
let dog = new Dog("旺财", 3, "公");
dog.run();
dog.sayHello();
抽象类、抽象方法
- 抽象类不能被实例化,只能被子类继承;
- 抽象类中可以定义抽象方法,但抽象方法不做具体实现,子类继承时必须实现具体的方法;
abstract class Animal {
public name: string;
constructor(name: string) {
this.name = name;
}
// 抽象类中定义抽象方法,不做具体实现,子类继承时必须实现具体的方法
abstract sayHello(): void;
}
class Dog extends Animal {
// 子类必须实现父类的抽象方法
sayHello() {
console.log("旺旺旺");
}
}
let dog = new Dog("旺财");
dog.sayHello();
// 抽象类不能实例化,只能被继承---这里会报错
let animal = new Animal("鱼");
接口
接口用于定义一个规范。
- 检查变量类型:
interface labelValue{
label:string;
}
// 在调用printLabel时,会根据接口的定义,检查传入的参数和类型;并且只检查那些必需属性是否存在,并且类型是否匹配。
function printLabel(labelObj:labelValue){
console.log( labelObj.label );
}
// 如果传入的没有传入label或类型不是string则会报错
let myObj2={ size:10, label:"Size 10 Object" };
printLabel(myObj2);
- 接口继承:
interface Shape {
color: string;
}
// 定义新的接口,并继承Shape接口
interface Triangle extends Shape {
sideNum: number;
}
// 声明变量遵循 Triangle 接口
let triangle = <Triangle>{};
triangle.color = "blue";
triangle.sideNum = 3;
triangle.sideNum1 = 4; // 这里会报错,遵循Triangel接口,只能定义color和sideNum
let square: Shape;
square.color = "red";
//报错
square.sideNum=4;
- 类接口:
// 定义接口ClockInterface,包含属性 currentTime:Date 和 方法getTime;
interface ClockInterface{
currentTime:Date;
getTime(d:Date);
}
// 类遵循接口 ClockInterface, 至少需要currentTime属性和实现getTime方法;
class Clock implements ClockInterface{
currentTime:Date;
age: number;
constructor(h: number, m: number){}
getTime(){
console.log("123");
}
}
let clock1=new Clock(30,40);
clock1.getTime()
- 接口继承类:
// 定义类 Point,包含属性x、y 和 方法log
class Point{
x:number;
y:number;
constructor(){}
log(){
console.log('123456');
}
}
// 接口继承一个类时,会继承类的成员但不包括其实现。
// 所以接口Point3d会继承类属性x、y和方法log,并且新增一个属性z
interface Point3d extends Point{
z:number;
}
// 变量遵循接口Point3d,只能包含x、y、z和log方法。
let point3d: Point3d={
x:1,
y:2,
z:3,
log(){
console.log('7777');
}
}
point3d.log();//7777
属性封装
- 提供get和set方法,在类外获取和修改属性;
- 类属性声明的简便方法;
class Animal {
/*
定义 public 属性,类内部和外部都可以访问
定义 private 属性,当前类内部可以访问
定义 protected 属性,当前类和子类可以访问
*/
private _name: string;
constructor(name: string) {
this._name = name;
}
// 提供get方法,在类外面访问_name属性
get name() {
return this._name
}
// 提供set方法,在类外面修改_name属性
set name(val: string) {
// 这里可以加一些对修改name的校验
this._name = val;
}
}
class Dog {
// 直接在构造函数中定义 public name,相当于先定义name属性,在constructor中赋值this.name = name;
/*
public name: string;
constructor(name: string) {
this.name = name;
}
*/
constructor(public name: string) {
}
}
let dog = new Dog("旺旺")
console.log(dog);
泛型
在定义函数或类时,如果遇到类型不明确时就可以使用泛型。
// 1. 当函数输入值和返回值类型不确定时,可以使用泛型代表输入和返回的类型,用于限制类型。
function fn<T>(a: T) : T {
return a;
}
// 2. 多个参数
function fn2<T, K>(a: T, b: K): T {
console.log(b);
return a;
}
// 3. 接口和泛型
interface Inter {
length: number;
}
// 表示泛型T必须实现接口Inter,即存在length属性
function fn3<T extends Inter>(a: T): number {
return a.length;
}
fn3("123");
fn3({length: 100});
// 4. 类
class MyClass<T>{
name: T;
constructor(name: T) {
this.name = name;
}
}
const mc = new MyClass("孙悟空"); // TS自动推断参数类型
const mc1 = new MyClass<string>("猪八戒"); // 指定泛型类型