console.log('hello TS!')
// 声明变量a,并且指定a的类型只能是number
let a : number;
a=10;
// 声明完变量后直接赋值
let c:boolean = true;
// 给函数的参数和返回值指定类型
function sum(a:number,b:number) : number{
return a + b;
}
sum(123,9)
// 可以使用 | 来连接多个类型,|符号代表或
let d : number | string;
d=123;
d='iwhdiud'
let e : "male" | "female"
// e的值只能是字符串male或者female
e = "male";
e = "female";
// any代表可以是任意类型,并且可以赋值给任意类型的变量
let f:any;
f=123;
f='234';
f=true;
// 如果声明了变量但是没有指定类型,则默认是any类型
let g;
// unknown类型的变量可以是任意类型,但是不能赋值给其他类型变量(比any类型更安全)
let h:unknown;
h=123;
if(typeof h === "number"){
//unknow类型要赋值的话必须先判断类型(h的类型必须和a的一样才可以赋值) 或者使用断言
a= h
}
/* 断言格式:
1. 变量 as 类型
2. <类型>变量
*/
a = h as number
a = <number>h
// void类型代表空,以函数为例,就是没有返回值的函数
function fn() :void{
return
}
// never类型代表永远不会有返回结果,用的很少
// function fn1() : never{
// throw new error('报错了')
// }
// {} 用来指定对象中可以包含哪些属性值并指定类型
// 属性名后面加上? 代表此属性是可选的,可写可不写
let obj : {name:string,age?:number}
obj={
name:'hahha',
age:99
}
// [propname:string]:any 表示可以在对象里面添加多个任意类型的属性
let obj2 : {name:string,[propname:string]:any}
obj2={name:'iii',a:1,b:true,oobj:{f:'00'}}
// 设置函数参数的类型和返回值的类型(形参:类型,形参:类型) => 返回值类型
let fun : (a:number,b:number) => number
fun = function(n1,n2){
return n1+n2
}
// 定义数组里面元素的类型: 类型[] 或者 array<类型>
let arr:string[]
arr = ['w','e','r']
// let arr2 : Array<number>
// arr2 = [1,2,3,4]
// 元组:就是固定长度的数组,语法: [类型,类型,类型]
let tot : [string,number,]
tot = ['decd',123]
// 枚举enum:就是把可能的情况列出来,使其他开发者知道其含义
enum Gender{
male=1,
female=0
}
let obj7 : {name:string,gender:Gender}
obj7 = {
name:'xue',
gender:Gender.female
}
// & 表示与,表示既要满足前面的类型又要满足后面的类型
let obj4 : {name:string} & {age:number}
obj4 = {name:'xye',age:89}
// 给类型起别名:type 别名 = 类型,此时这个别名就可以代表这个类型
type myType = string
let str:myType
str='jidjsn'
type myType2 = 1|2|3|4|5
let num :myType2
num = 1
TS高阶
// 使用class定义一个类
class Person{
// 直接定义的属性是实例属性,必须通过new一个此对象来访问
name:string = 'xuejiay'
// static定义的属性是 静态属性,可以通过 类名.属性名 直接访问,不能通过对象访问
static age:number = 12
// readonly开头的属性是只读属性 ,不可以修改
readonly gender:string = 'female'
// 实例方法
say(){
console.log('hello')
}
// 静态方法, 通过类名.方法 直接访问
static say(){
console.log('hello')
}
}
const per = new Person()
console.log(per.name,Person.age,per.say(),Person.say())
// 构造函数 construtor:在创建对象的时候会执行
// 一般定义类class中,都要用构造函数去初始化属性
class Dog{
// 给Dog类定义属性类型
name:string
age:number
constructor(name:string,age:number){
// 构造函数会在调用此类的时候执行
// 可以通过this向新建的对象添加属性
this.name = name,
this.age = age
}
sayHI(){
// 谁调用这个Dog类,this就指向谁
console.log(this.name)
}
}
let dog1 = new Dog('小黑',12 )
let dog2 = new Dog('小白',88)
dog2.sayHI()//此时里面的this是指向dog2
// 继承: 子类 extends 父类
// 子类可以继承父类中所有的属性和方法
// 子类中可以定义属于自己的属性和方法
// 如果子类重写父类中的方法,则子类重写的方法会覆盖掉原先父类的方法
class Animal{
name:string
age:number
constructor(name:string,age:number){
this.name = name
this.age = age
}
dark(){
console.log('动物在叫')
}
}
class Cat extends Animal{
// sayCat() 是属于cat类独有的方法
sayCat(){
console.log(`${this.name}在叫--`)
}
dark(){
console.log(`${this.name}重写了父类的方法`)
}
}
class Lion extends Animal{
}
const cat = new Cat('小猫',12)
cat.dark()
cat.sayCat()
const lion = new Lion('小狮子',20)
lion.dark()
// super关键字:代表当前子类的父类,此时super = father
// 如果在子类中写构造函数,会出现重写父类构造函数的情况
// 重点:所以子类写的构造函数里,必须调用一次父类的构造函数!!!!
// super() 就代表父类的构造函数
// 也可以通过super.属性,来调用父类的东西
class father{
name:string
constructor(name:string){
this.name = name
}
}
class Son extends father{
age:number
constructor(name:string,age:number){
super(name)
this.age = age
console.log(super.name)
}
}
const son = new Son('儿子',19)
// 抽象类 abstract: 以abstract开头的类是抽象类
// 抽象类只能用来被继承,不能用它来创建实例
// 以abstract开头的函数是抽象函数,抽象函数只能写在抽象类中
// 抽象函数没有函数体,相当于只是声明有这个函数
// 子类必须要重写这个抽象函数!
abstract class fa {
name:string
constructor(name:string) {
this.name = name
}
abstract run():void
}
class so extends fa {
run() {
console.log('子类必须重写父类的抽象函数')
}
}
// 接口interface : 用接口来定义一个类/对象中应该包含的属性和方法,定义对象用法有点类似用type定义对象类型的别名
// 接口可以重复定义,使用该接口创建对象/类时要同时满足里面的属性方法
// 接口里的属性和方法都不能有实际的属性值和函数体
// 也就是说,接口里的函数是抽象函数
// 接口不仅可以定义对象 : const 对象:接口 = {} ,也可以用来定义类 : class 类名 implements 接口 {}
// 抽象类abstract是用来继承的,接口是用来定义一个规范
interface myInterFace{
name:string
age:number
say():void
}
interface myInterFace{
gender:string
}
// 接口定义对象
const people:myInterFace = {
name:'xjw',
age:22,
gender:'female',
say(){
console.log('对象里面实现接口的抽象函数')
}
}
// 接口定义类
class myClass implements myInterFace{
name:string
age:number
gender:string
constructor(name:string,age:number,gender:string){
this.name = name
this.age = age
this.gender = gender
}
say(){
console.log('类里面实现接口的抽象函数')
}
}
const stu = new myClass('xjw',12,'male')
stu.say()
// public: 公有属性,可以在任意位置访问和修改
// private: 私有属性,只能在类内部进行访问和修改
// 可以在类中添加方法使外部可以间接访问和修改到私有属性
// 访问私有属性方法: get 方法名(){return this.私有属性名} 外部调用: 对象.方法名
// 修改私有属性方法: set 方法名(形参){this.私有属性 = 形参} 外部调用: 对象.方法名 = 实参
// prptected: 受保护属性,只能在当前类和其子类中访问和修改
class Student{
public name:string
private score:number
protected gender:string
constructor(name:string,score:number,gender:string){
this.name = name
this.score = score
this.gender = gender
}
get getScore(){
return this.score
}
set setScore(value:number){
this.score = value
}
}
const stu1 = new Student('xjw',11,'male')
stu1.name //对象调用公有属性
stu1.getScore//对象通过调用类的内部方法来访问私有属性
stu1.setScore = 100//对象通过调用类的内部方法来修改私有属性的值
class sstu extends Student{
//受保护属性在外部访问不了,只能在其当前类和继承的子类中使用
test(){
console.log(this.gender)
}
}
const sstu1 = new sstu('sxk',23,'female')
sstu1.test()
// 语法糖: 在constructor的形参中使用属性修饰符后,简化了一些操作,效果和以下注释的代码一样
// class C {
// name:string
// age:number
// constructor(name:string,age:number){
// this.name = name
// this.age = age
// }
// }
class C {
constructor(public name:string,public age:number){
}
}
const c1 = new C('xjw',10)
// 泛型:当不确定变量或者返回值类型的时候就使用一个变量代替当一个占位符
// <T,K>泛型可以写多个,在函数或者类中都可以使用泛型
//fx<number,string>() 调用函数或者类是要在后面写其泛型占位符是代表着什么类型
function fx<T,K>(a:T,b:K):T{
return a
}
fx<number,string>(1,"hello")