目录
一、基础静态类型和对象类型
二、类型注解和类型推断
三、元组的使用和类型约束
四、接口
五、类
六、联合类型和类型保护
七、枚举
八、泛型
九、tsconfig.json文件
TypeScript 其实就是 JavaScript 的超集,也就是说 TypeScript 是建立在 JavaScript 之上的,最后都会转变成 JavaScript。TypeScript我也是一个初学者,在这里,我会简单总结一些关于TypeScript的特性,具体细节感兴趣者可参考中文官方文档。
TypeScript的主要特性如下:
- 基础静态类型和对象类型
- 类型注解和类型推断
- 元组的使用和类型约束
- 接口
- 类
- 联合类型和类型保护
- 枚举
- 泛型
- tsconfig.json文件
一、基础静态类型和对象类型
基础静态类型
TypeScript最大的一个特点就是变量是强类型的,也就是说,在声明变量的时候,我们必须给他一个类型。常用的基础静态类型类型有:string、null、undefined 、Array、 boolean、 any 、void、 Tuple 、enum等
const test1:string = "s"//字符串
const test2:number = 1//数字
const test3:null = null//null
const test4:Array<number> =[1,2]//数组
const test5:boolean = false//布尔
const test6:any = 10//任意类型
const test7:undefined = undefined//undefined
对象类型
对象类型大概可以分为四种
//对象类型--我们可以直接使用{propertyName:type,...}的形式来约束类型的名称和类型
const ts:{name:string,age:number} = {name:"hello",age:22}
//数组类型--基础静态类型的数组也可以为对象类型,这里就用string类型示例,其他类型数组都差不多
const strArr:string[] =['a','b']
//数组类型也可以这样表示
const strArr:Array<string> = ['1','2']
//类类型--需要自己先创建一个类,然后声明属性时约束其为创建的类
class Class1{
name:string;
age:number
}
const class1:Class1 = {name:"a",age:12}
const class2:Class1 = new Class1()
//函数类型--声明变量为函数和返回值的类型
const func:()=>string = ()=>"hello TypeScript"
对象数组
const man: { name: string, age: number }[] = [
{ name: "小A", age: 22 },
{ name: "小B", age: 22 },
]
这种形式看起来比较麻烦,而且如果有同样类型的数组,写代码也比较麻烦,TypeScript 为我们准备了一个概念,叫做类型别名(type alias)。定义别名的时候要以type关键字开始。
//type alias 类型别名
type man = { name: string, age: number };
//然后再定义数组的时候我们就可以用别名了
const manArr: man[] = [
{ name: "小A", age: 22 },
{ name: "小B", age: 22 },
]
还有我们如何控制一个数组中既有数字或者有字符串呢, 很简单,只要加个()
,然后在里边加上|
就可以了,具体如代码所示。
const arr3: (number | string)[] = [1, "2", 3];
二、类型注解和类型推断
类型注解即我们声明变量时指明了变量的类型,这就变量注解。
let count1:number;
TypeScript里,在有些没有明确指出类型的地方,类型推论会帮助提供类型。
const x = 2;
变量x的类型被推断为数字。这种推断发生在初始化变量和成员,设置默认参数值和决定函数返回值时。
三、元组的使用和类型约束
元组和数组类似,但是类型注解时会不一样,元组是对数组中的每一个元素都确定了类型。其实你可以把元组看成数组的一个加强,它可以更好的控制或者说规范里边的类型。
//元组
const xiaoge: [string, string, number] = ['a', 'b', 28];
//元组数组
const xiaoge: [string, string, number][] = [['a', 'b', 28],['a1', 'b1', 28],['a2', 'b2', 28]]
四、接口
接口声明示例:如下代码所示,我们可以在接口中指定属性的类型,属性名?代表当前属性为可选字段(可以赋值,也可以不赋值)
[propname:string]:any 用于新增一些任意属性,属性的名字是字符串类型,属性的值可以是任何类型。
interface Person {
name: string;
age: number;
height?: number;
[propname:string]:any;//any为任意类型
say():string//可声明函数
}
接口和接口之间可以继承,使用关键字extends,子接口将拥有父级接口的所有属性和函数
interface Student extends Person{
studentNo:string
}
//使用接口进行注解,被注解的变量需要对接口中所有不是可选属性的属性进行赋值,不然代码就会提示错误
const stu:Student = {name:"小A",age:20,studentNo:"A01",say() {
return "我是小A"
},}
使用类实现接口,实现需要用到关键字implements,也需要对接口中所有不是可选属性的属性进行赋值,函数也必须实现,不然代码就会提示错误
class StuB implements Student{
name = "小B"
age = 22
studentNo = "B01"
say(){return "hello"}
}
五、类
TypeScript类主要内容有:
- 类的基本使用
- 类的继承、重写和super关键字
- 类的访问类型
- 类的构造函数
- 类的Getter、Setter、Static和只读属性
- 抽象类
类的基本使用
就像这样,可以声明一些变量和方法,使用类时可以通过new关键字生成对象
class Animal{
content = "动物";
say(){
return this.content
}
}
const animal:Animal = new Animal()
类的继承、重写和super关键字
继承:使用extends关键字,子类将拥有父类的所有属性和方法,当然也可以自己的属性和方法
class Bird extends Animal{
fly(){
return "I can fly"
}
}
const bird:Bird = new Bird();
console.log(bird.say())//动物
console.log(bird.fly())//I can fly
重写:类的重写主要是子类对父类函数的重写,就是父类有一个函数,子类定义一个与父类同名同参的函数,然后这个函数可以与父类有不一样的实现。
//Animal类也是有say()函数的,这里子类再次定义say()函数就是对父类函数的重写
class Bird extends Animal{
say(){
return "I am a bird"
};
fly(){
return "I can fly"
}
}
super关键字:用于子类调用父类的属性和方法
class Bird extends Animal{
say(){
return super.content+ "-- bird"//调用父类函数就可以用super.say()
};
fly(){
return "I can fly"
}
}
类的访问类型
类的访问类型只有三种public、private、protected
- public -- 代表类的内部和外部对可以使用
- private -- 代表只允许内的内部调用,子类也无法使用
- protected -- 代表类内部和其子类可以使用,内的外部无法使用
//public
class Person {
public name = "person";
public sayHello() {
console.log(this.name + " hello");
}
}
const person = new Person()
console.log(person.name);//person(因为是public,所以外部能访问到Person.name)
person.sayHello();//person hello
//private,它的子类访问不到name属性
class Person2 {
private name = "person";
public sayHello() {
console.log(this.name + " hello");
}
}
const person2 = new Person2()
//console.log(person2.name);编译不通过Property 'name' is private and only accessible within class 'Person2'.
person2.sayHello();//person hello
//protected,它的子类可以访问到name属性
class Person3 {
protected name = "person";
public sayHello() {
console.log(this.name + " hello");
}
}
const person3:Person3 = new Person3()
//console.log(person3.name);编译不通过:Property 'name' is protected and only accessible within class 'Person3' and its subclasses.
person3.sayHello();//person hello
类的构造函数
类构造函数的基本使用,使用constructor函数
class TestA{
public name:string;
constructor(name:string){
this.name = name
}
}
//可以简写为
class TestA{
constructor(public name:string){
this.name = name
}
}
const t1:TestA = new TestA("小A");
console.log(t1.name);//小A
子类继承父类后构造函数中必须使用super调用父类的构造函数
//继承的构造函数
class TestB extends TestA{
constructor(public age:number){
//在子类的构造函数中必须写super(),若不写会报错
super('小B')
this.age = age;
}
}
const testB:TestB = new TestB(23)
console.log(testB.name);//小B
console.log(testB.age);//23
类的Getter、Setter和Static
当变量被声明为私有变量时,无法直接访问到属性值,这里就可以通过设置get和set函数来取值赋值,使用时就和获取public变量一样了。
class GSClass{
constructor(private _age:number){}
get age(){
return this._age
}
set age(age:number){
this._age = age
}
}
const gs = new GSClass(23);
gs.age = 24;
console.log(gs.age);
static用于不需要实例化对象就可以调用类的方法
class Boy{
static sayLove(){
return "I Love You"
}
}
console.log(Boy.sayLove());
只读属性
使用readonly关键字进行修饰,顾名思义,只读属性只用于数据读取,不能进行赋值
class Server{
public readonly _name:string;
constructor(name:string){
this._name = name
}
}
const user = new Server("rr")
console.log(user._name);
抽象类
使用abstract关键字修饰的类为抽象类
抽象类中可以声明抽象函数(也可以有普通函数),也是用abstract关键字修饰
子类继承抽象类必须实现抽象类中所有抽象方法
//抽象类
abstract class A{
abstract skill();
}
class B extends A{
skill() {
console.log("s1");
}
}
六、联合类型和类型保护
interface Waiter {
anjiao: boolean;
say: () => {}
}
interface Teacher {
anjiao: boolean;
skill: () => {}
}
//
function judgeWho(person: Waiter | Teacher) {
//断言
if (person.anjiao) {
(person as Teacher).skill();
} else {
(person as Waiter).say();
}
}
function judegeWhoTwo(person: Waiter | Teacher) {
if ("skill" in person) {
person.skill();
} else {
person.say();
}
}
function add(first: string | number, second: string | number) {
if (typeof first === "string" || typeof second === "string") {
return `${first}${second}`
}
return first + second
}
class NumberObj{
count:number;
}
//instanceof 只能用在类上
function addObj(first: object| NumberObj,second:object| NumberObj){
if(first instanceof NumberObj && second instanceof NumberObj){
return first.count + second.count
}
return 0;
}
七、枚举
//默认值从0开始
enum Status {MESSAGE,SPA,DABAOJIAN}
//这样枚举就从1开始了
//enum Status {MESSAGE = 1,SPA,DABAOJIAN}
function getServe(status:number){
if(status === Status.MESSAGE){
return "message"
}else if (status === Status.SPA){
return "spa"
}else if (status === Status.DABAOJIAN){
return "dajiao"
}
}const result = getServe(Status.MESSAGE);
// const result = getServe(0);
console.log(result);
///这样输出为数字 0 , 1 ,2
console.log(Status.MESSAGE);//0
console.log(Status.SPA);//1
console.log(Status.DABAOJIAN);//2
//反查 (其实数字代表的是具体枚举代表的值)
console.log(Status[0]);//MESSAGE
console.log(Status[1]);//SPA
console.log(Status[2]);//DABAOJIAN
八、泛型
函数上泛型的使用
function join(first:string|number ,second:string|number){
return `${first}${second}`
}
join("ss","com")
//保证first和second的类型一致
function join2<T>(first:T ,second:T){
return `${first}${second}`
}
join("ss","com")
join2<number>(1,2);
//数组
function myFunc<T>(params:Array<T>){
return params;
}
myFunc<string>(["123","456"]);
//多种类型
function myFunc2<T,P>(first:T,second:P){
return `${first}${second}`
}
myFunc2<string,number>("2",1);
类上泛型的使用
interface TT{
name:string
}
class SelectGirl<T extends TT>{
constructor(private girls:T[]){}
getGirl(index:number):string{
return this.girls[index].name;
}
}
const selectGirl = new SelectGirl([{name:"小A"} ,{name:"小B"},{name:"小C"}]);
console.log(selectGirl.getGirl(1));
九、tsconfig.json文件
相关链接:编译选项 · TypeScript中文网 · TypeScript——JavaScript的超集