ts 笔记
1. ts 基础类型
冒号后面叫做 类型注解
// 使用ts声明一个字符串类型的变量
let name:string = 'zrs'
// 使用ts声明一个数字类型的变量
let age:number=18
// 使用ts声明一个布尔类型的变量
let flag:boolean=false
// 声明 nul 类型的变量 只能赋值为 null
let aaa:null=null
// 声明 undefined 类型的变量,只能声明为 undefined
let bbb:undefined=undefined
2. ts数组
// 声明一个只能装 数字类型的数组
let arr1:number[]=[]
// 声明一个只能装 字符串类型的数组
let arr2:string[]=[]
// 使用泛型声明一个数组 该数组只能装 数字类型的元素
let arr3:Array<number>=[]
// 使用泛型声明一个数组 该数组只能装 字符串类型的元素
let arr4:Array<string>=[]
3. any 类型
// 声明一个 any 类型的变量,那么这个变量可以赋任何类型的值
let a:any;
a=123
a='asd'
a=true
// 以上代码都不会报错
// 因为 any 类型可以赋值给 任何类型,所以下面的代码不报错
let e:number=a
// 在ts中 声明变量的时候,不注解,不赋值,那么 就是隐式的任意类型
let b;
b=100
b='sdf'
// 以上代码 不会报错
// 在声明变量的时候,不注解,直接复制,那么 ts 会根据值推断变量的类型,那么这个变量以后就只能被赋相同类型的值
let c=100
// 报错
// c="asd"
// 不会报错
c=123
4. unknow 类型
// unknown 类型是一个安全的any类型,
// 因为他虽然可以被赋值任何类型的数据,但是只能赋值给unknown类型或者any类型的变量
let a:unknown;
a='123'
a=123
let c:string="safd";
// 报错 因为 c 是字符串类型,a 是 unknown类型,unknown只能赋值给unknown类型或者any类型的变量
// c=a
let d:unknown=a
let e:any=a
怎样将unknown类型赋值给上面的 c 切不报错了?有三种方式
// 第一种方式,缩小范围
if(typeof a=='string'){
c=a
}
// 第二种方式 类型断言
c=a as string
// 第三种方式 泛型
c=<string>a
5. void 类型
// void 类型表示空 通常在限制函数没有返回值的时候使用
function func1(x: number, y: number):void{
console.log(x,y);
// 这一行报错
// return x+y
}
6. never 类型
// never 表示永远没有返回值
function fun():never{
throw new Error("error"); // 抛出错误之后,这行代码之后的代码就永远不会执行了,所以never不会报错
}
7. 对象类型
类型推断的方式
// 这里赋值的时候,类型就已经固化了, 就只能赋值初始化的时候的类型的值
let person={
name:'zrs', // 这里已经推断为 person.name 为字符串了
age:21 // 这里已经推断 person.age 为数字类型了
}
// 因为上面已经推断了 那么这里person.name 就只能是字符串了
person.name = 'aaa'
// 因为上面已经推断了 那么这里person.age 就只能是数字了
person.age =22
类型注解的方式
// 对象的类型注解的方式
let person:{name:string, age:number,sex:string}
person={
name:'zrs',
age:12,
sex:'男'
}
// 以上这种方式有一个缺点,就是补不能在添加属性了
// 所以下面这句代码报错了
// person.money=222
// 在属性值后面 添加了一个 问号 表示这个属性值是可选的,就是可有可无
let person:{name:string, age?:number,sex?:string}
// 不会报错 因为 age 和 sex 可有可无
person={
name:'zrs',
}
// propName 的类型为string 属性值的类型为any
let person:{name:string, [propName:string]:any}
person={
name:'zrs',
age:20,
sex:'男',
money:222
}
person.sex='女'
console.log( person.sex);
// 以上这种方式,可以在对象有很多个不确定属性的时候使用
8. 函数
// 普通函数的声明
/**
* c的后面添加了一个问号,所以可有可无
* 限制返回值是一个number类型
*/
function fun(a:number, b:number, c?:number):number {
return a+b
}
console.log(fun(1,2));
// 箭头函数的声明
const func2=(a:string, b:string, c?:string):string =>{
return a+b;
}
// 箭头函数的声明
const func1:(a:string, b:string, c?:string) => string=(a1:string, a2:string, a3?:string)=> a1+a2+a3
9. 匿名函数
// 匿名函数
let nums:number[] = [1,3,2,5,24,5,2,3,53,3,123,0];
// 匿名函数 可以写 参数以及返回函数的类型注解
// 这行代码不会报错
// nums.sort((a:number, b:number):number => { return a-b; });
// 也可以不写注解,机制会自行推断
// 这行代码也不会报错
nums.sort((a, b) => { return a-b; });
console.log(nums);
10. 联合类型
|
// 之前声明的变量只能有一种类型
let uname: string='zrs'
// 但是联合类型就可以使变量有多种类型
let demo:number|string
demo=0
demo='zrs'
// 以上代码不会报错
// 定义一个变量保存函数的返回值
let flag:boolean|null|undefined
flag=false
flag=null
flag=undefined
// 以上代码不会报错
// 联合声明在函数中使用
function func(a:number|string,b:number|string):void|number{
}
// 联合类型在数组中使用
// let arr:number[]=[1,2,'12'] // 报错
let arr:number[]=[1,2] // 这种方式声明的数组只能存放一种类型的元素
// 联合类型的数组声明
let arr2:(number|string)[]=[12,'qwer']
arr2.push("asdf")
arr2.push(123)
console.log(arr2);
&
// 一个变量怎么能既是字符串类型又是数字类型了,这个代码就是没有意义的,虽然不会报错
let uname:string&number;
// & 一般适合用在这儿了
let person:{name:string} &{age:number}
person={
name:'zrs',
age:12
}
console.log(person);
11. 字面量类型声明
// 变量的字面量声明的方式
let a:10 // 这行代码相当于声明一个变量 变量的值只能是10
a=10
// a=11 // 这种情况的话 a会报错
// 字面量声明类型的应用场景
let sex:'male'|'female'
sex='male'
sex='female'
console.log(sex);
12. 元组 tuple
// 声明一个数组
let arr:number[] = [];
/**
* ts中元组是什么?
* 元组是不同类型的元素组成的数组
*/
// 声明一个元组
// 元组的每一个元素的数据类型是意义对应的
let mytuple:[string, number] = ['as',1];
// let mytuple:[string, number] = [1,'as']; // 报错
// 元组定义之后,只能添加其声明的时候的数据类型,添加其他类型会报错
mytuple.push('a')
console.log(mytuple);
mytuple.pop()
mytuple.push(100)
// mytuple.push(true) //报错
console.log(mytuple);
// 数组嵌套元组---以后可能会用到
let arr4:[string, number][]=[['a',1],['b',1],['c',1],['d',1]]
13. 枚举 enum
// 限制一个变量只能是固定的几个值,可以使用字面量的方式
let sex:'male'|'female';
sex='male'
sex='female'
// sex==10 // 报错,因为 声明的是字面量类型,导致只能赋值为 'male'或者'female'
// console.log(sex);
// 当然,还有一种方式可以实现,那就是枚举
enum sex2{
male,
female
}
// 调用
// console.log(sex2.male); // 0
// console.log(sex2.female); // 1
console.log(sex2[0]); // male
console.log(sex2[1]); // female
14. 类型别名
// 类型别名 使用关键字 type
// 字面量变量的类型别名
type sex='male'|'female'
let userSex:sex='male'
console.log("userSex:",userSex);
// 函数的类型别名
// 给注解取一个别名
type func=(a:number,b:number)=>number
// 利用别名来声明函数 这里的func 类似于声明简单数据类型后面的number/string
const getSum:func=(c,d)=>c+d
console.log("getSum:",getSum(1,1));
// 对象的别名
type person={
name:string,
age:number,
}
// 利用对象的别名声明对象
let parent1:person={
name:'zrs',
age:20
}
// 利用对象的别名声明对象
let son1:person={
name:'zzz',
age:12
}
// 别名就是将一种注解,赋值给某个值,然后这个值可以复用,可复用的值就是别名
15. 类型断言
/**
* 什么是类型断言
* 类型断言就是告诉 ts 这个变量就是这个类型,不需要你去推断了。
*/
function getSum(a:number|string){
let len1:number;
// 这种方式是缩小类型范围
// if(typeof a == "string"){
// len1= a.length
// }else{
// len1=0
// }
// 类型断言的尖括号语法
// len1=(<string>a).length
// 类型断言之 使用 as 语法
len1 = (a as string).length
console.log(len1);
}
getSum('asdfghj')
// 字面量类型的变量和常量之间的区别
// 字面量类型的变量,可以再赋值,但是只能是声明的时候的那个值
let myname:'zrs'
myname='zrs'
// const 声明的不能再赋值
const myname2:string='abcd'
// myname2='abcd' // 报错
/**
* 使用 const 为数据做类型断言,很常用,将当下的数据的类型转换为固定的类型
* 根据具体的值转化类型
*/
// 将推断类型转化为字面量类型
let uname='asdc' as const
// uname='sdaf' //报错
// 因为 上面的语句将其转换为 字面量类型了,所以只能赋值为 'asdc'
uname='asdc'
console.log(uname);
// 将推断类型的数组转化为元组
let arr=['asdds',1,'sad',22] as const
// arr[0]='asdds' // 报错,只读,不能更改
// 将推断类型的数组转化为元组-第二种方式
let arr2=<const>['asd',12]
// arr2[0]='asd' // 报错,只读,不能更改
// 将推断类型的对象转换为只读
let obj={
uname:'zrs',
age:12
} as const
// obj.uname='zrs' // 报错 只读 不能更改
function fun(){
let str:string='qwertyuiop'
let funSub=(a:number,b:number)=>a+b
return [str,funSub]
}
// let [str,funSub]=fun()
// 报错 没有类型断言,所以ts不知道funSub 是函数还是字符串
// funSub()
// 这里做了类型断言,所以不会报错,ts可以正确执行代码 这是第一种方法
// 赋值的时候断言
// let [str,funSub]=fun() as [string,Function]
// console.log(str);
// console.log(funSub(10,10));
// 第二种方式,在使用的时候断言
let [str,funSub]=fun()
console.log(str as string);
// console.log((funSub as Function)(20,20)); // 使用的时候,第一种方式断言
console.log((funSub as (a:number,b:number)=>number)(20,20)); // 使用的时候,第二种方式的断言
// 以上方法都是在得到结果之后断言的,不方便
// 在返回的时候,直接断言最合适
function fun2(){
let str:string='qwertyuiop12345678'
let funSub=(a:number,b:number)=>a+b
// return [str,funSub] as[string,Function] // 第一种方式
// return [str,funSub] as[typeof str,typeof funSub] // 第二种方式
return [str,funSub] as const // 第三种方式
}
let [str2,funSub2]=fun2()
// let [str2,funSub2]=fun2() as const // 报错 因为这里是返回的值,已经不能明确类型了
console.log(str2 );
console.log((funSub2)(100,30))
为什么会有类型断言这种玩意儿?
- 因为在声明变量的时候,有联合类型等,导致ts不知道对应的变量的具体类型,所以需要手动告诉ts该变量是什么类型。
非空断言
let str:string='zrs'
// 因为我在 tsconfig.json 中配置了 "strict": true, 所以下面的语句报错
// str=null
// str=undefined
// 非空断言
let str2:string|null|undefined;
str2='asdfghjkl'
console.log(str2!.length);
/**
* 在 变量后面添加 ? 表示这个变量可有可无
* 在 变量后面添加 ! 表示告诉ts这个变量一定是非空值
*/
16. 函数类型
// 给函数一个注解
let fun:(a:number,b:number)=>number=(n:number,m:number)=>{
return 10
}
// 使用别名的方式
type myfun=(a:number,b:number)=>number
let fun2:myfun=(n,m)=>{
return n+m
}
// 回调函数使用类型注解 使用的是别名的方式
function calc(a:number,b:number,fun:myfun){
return fun(a,b)
}
let res=calc(10,21,(n,m)=>{
return n+m
})
console.log(res);
// 对象中定义的函数的注解
let person:{
uname:string,
age:number,
fun:(a:number,b:number)=>void
}
person={
uname:'zrs',
age:18,
fun:(a,b)=>{
console.log(a+b);
}
}
person.fun(10,11)
type user={
uname:string,
age:number,
func:(n:number,m:number)=>void
}
const person1:user={
uname:'zrs',
age:20,
func:(n,m)=>{
console.log(n+m);
}
}
函数的可选参数
// 可选参数
type func = (a: number, b?: number) => number
// 再参数后面添加一个 ?表示这个参数是可选的,表示可有可无
const myfun: func = (n: number, m?: number) => {
if (typeof m === "number") {
return n + m
}
return n
}
let res = myfun(1, 1)
console.log(res);
// 函数的参数的默认值
const myfun2 = (a: number = 1, b: number = 2): void => {
console.log(a, b);
}
myfun2()
myfun2(3, 4)
// 函数的可变参数(剩余参数) 使用扩展运算符
// 这里的第三个参数是一个展开的任意类型的数组 用来接收剩余的参数
const myfunc3 = (a: number, b: number, ...args: any[]): void => {
console.log(a, b, args);
}
myfunc3(1, 2, 3, 4, 'qwertyui')
函数的重载
// 函数的重载
/**
* 函数重载就是 同一个函数名 因为参数类型不同,或者参数类型的顺序不一样而执行不同的函数体的情况
*/
// 可以这样理解 先定义一个框架,没有写方法体
function fun(a: number, b: number): number
function fun(a: string, b: string): string
function fun(a: number, b: string): string
function fun(a: any, b: any) {
console.log("a", a, "b", b);
return a + b
}
fun(10, 12)
fun('s', 'sdddd')
fun(11, 'asdf')
17. 类
// ts 中类的写法
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
eat() {
console.log(this.name + "正在吃饭", this.age + "岁");
}
}
const p1 = new Person('zrs', 20)
p1.eat()
console.log(p1.name);
console.log(p1.age);
// 类的继承(又叫做类的扩展)
// ts 中类的继承
class Son extends Person {
money: number
hobby: string
constructor(name: string, age: number, money: number, hobby: string) {
super(name, age)
this.money = money
this.hobby = hobby
}
study() {
console.log(this.name + "正在学习");
}
}
const s1 = new Son('zts', 11, 1000, '打篮球')
s1.study()
// ts 中方法的重写
/**
* 什么是方法的重写?
* 就是在子类中写一个与父类中名字一样的方法,用来覆盖父类中的方法,叫做重写
* 一般在父类的方法不能满足子类的使用要求的时候调用
* 那么又想要调用父类被覆盖的方法又怎么办?使用 super.父类中被重写的方法() 即可
*/
class Sister extends Person {
sex: string
constructor(name: string, age: number, sex: string) {
super(name, age)
this.sex = sex
}
// 重写父类中的 eat() 方法
eat() {
console.log("先吃饭再学习");
console.log(this.name + "吃完饭了,去学习去了");
}
BigDinner() {
// 这里调用父类中被重写的方法 eat
super.eat()
console.log("吃大餐");
}
}
const s2 = new Sister('zzz', 11, '女')
s2.eat()
s2.BigDinner()
类的访问修饰符
public
// 类中的访问修饰符
/**
* 类中的访问修饰符有:
* public =>公共的
* private => 私有的
* protected =>受保护的
* readonly =>只读
*/
/**
* public 限制下
* 可以在类的内部访问修改
* 可以在类的外部访问修改
*/
class Person {
public name: string
public age: number
public constructor(name: string, age: number) {
this.name = name
this.age = age
}
public say() {
console.log("my name is " + this.name);
}
}
const p1 = new Person('zrs', 20)
p1.say()
private
/**
* private 限制下的属性和方法 只能在自己中访问修改
*/
class Person {
private name: string
private age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
say() {
/**
* private 限制下的属性和方法 只能在自己中访问修改
*/
this.name = "小张"
console.log("my name is " + this.name);
}
}
const p1 = new Person('zrs', 20)
p1.say()
// p1.name="zrs1111" // 报错 私有属性,只能在类中访问
// console.log(p1.name); // 报错 私有属性,只能在类中访问
protected
/**
* protected =>受保护的 限制的属性和方法 只能在自己和自己的孩子类中访问和修改
*/
class Person {
protected name: string
protected age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
say() {
this.name = "小张"
console.log("my name is " + this.name);
}
}
const p1 = new Person('zrs', 20)
p1.say()
// p1.name='zrs2222' // 报错 只能在类中或者子类中访问
// console.log(p1.name); // 报错 只能在类中或者子类中访问
class Son extends Person {
hobby: string
constructor(name: string, age: number, hobby: string) {
super(name, age)
this.hobby = hobby
}
eat() {
console.log("我是 " + this.name + " 我正在吃饭");
}
}
const s1 = new Son("小小张", 1, "rap")
s1.eat()
// s1.name = '小小小张' // 报错 因为父类使用了 protected 限制,只能在父类或者子类中访问
// console.log(s1.name); // 报错 因为父类使用了 protected 限制,只能在父类或者子类中访问
readonly
/**
* readonly =>只读 该修饰符的限制下,只能被初始化一次 然后就不能修改了
*/
class Person {
readonly name: string
readonly age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
say() {
// this.name = "小张" // 报错 因为这个是只读属性,只能初始化的时候赋值一次
console.log("my name is " + this.name);
}
}
const p1 = new Person('zrs', 20)
p1.say()
// p1.age=20 // 报错只读属性
console.log(p1.name); // 可以访问,不能修改
声明的类也可以作为一个类型
/**
* 将类作为另一个类的属性的类型
*/
class Phone {
brand: string
constructor(brand: string) {
this.brand = brand
}
}
class Person {
name: string
age: number
phone: Phone // 将类作为一另一个类的属性的类型
constructor(name: string, age: number, phone: Phone) {
this.name = name
this.age = age
this.phone = phone
}
say() {
console.log("my name is " + this.name);
}
}
const p1 = new Person('zrs', 20, new Phone('huawei'))
p1.say()
console.log(p1.phone.brand);
p1.phone.brand = "huawei 99"
console.log(p1.phone.brand);
ts 中的类的属性和方法的封装
/**
* 面向对象有四大特点:
* 封装
* 继承
* 多态
* 抽象
*/
/**
* 利用类的修饰符,可以实现对类的属性和方法的封装
* 为什么要进行封装?
* 将有用的东西暴露给用户,其他的东西就自己藏起来。
*/
class Person {
name: string
private _sex: string
constructor(name: string, sex: string) {
this.name = name
this._sex = sex
}
// ts 中提供的setter 设置值专用
set setSex(sex: string) {
this._sex = sex
}
// ts 提供的getter 获取值专用
get getSex() {
return this._sex
}
set setName(name: string) {
this.name = name
}
get getName() {
return this.name
}
run() {
console.log("运动");
this.go()
this.back()
}
private go() {
console.log("前进");
}
private back() {
console.log("后退");
}
}
const p1 = new Person('zrs', '男')
p1.run()
console.log(p1.getSex);
p1.setSex = "nv"
console.log(p1.getSex);
static
// 类中 static 使用
/**
* 在类的属性和方法前面添加 static 这个属性或者方法就变成了 静态属性和方法,为这个类所有
*/
class Student {
// 静态属性
static school: string = "cczx"
name: string
constructor(name: string) {
this.name = name
}
static sayMySchool() {
// 在静态方法 中调用静态属性或者方法 使用 this.属性名或者方法名 这里的this指向的是 Student 不是类实例化的对象
console.log("我的学校是" + this.school);
}
say() {
// 在非静态的方法中使用 静态属性或者方法 语法:类名.静态属性或者方法
console.log("我是" + this.name + "我是" + Student.school + "的");
// 非静态方法中的this指向的是实例化之后的对象
}
}
Student.sayMySchool()
console.log(Student.school);
const s1 = new Student('zrs')
/**
* 类中的静态属性和方法,对象不能直接使用的
*/
// s1.school // 报错
s1.say()
18. 抽象类
/**
* 抽象类
* 抽象类是一个特殊的类,一个类中如果有一个抽象方法,那么这个类就是抽象类。
* 抽象类不能实例化
*
* 抽象方法
* 抽象方法没有方法体。
*/
// 使用 abstract 来声明一个抽象类
abstract class Person {
name: string = 'zrs'
// 抽象属性
abstract money: number
say() {
console.log("hello");
}
// 抽象方法 因为类中有一个抽象方法,所以类的前面也必须添加 abstract
abstract run(): void
// 抽象方法
abstract back: () => void
}
/**
* 抽象类可以被继承,但是继承之后的类依然需要是抽象类,否则需要将继承的抽象类中的方法或者属性全部实现
*/
// 抽象类 继承 抽象类
abstract class Son extends Person {
sex: string
constructor(sex: string) {
super()
this.sex = sex
}
}
// 使用正常的类继承抽象类
// 这个类就可以实例化了
class Student extends Person {
money: number;
constructor(money: number) {
super()
this.money = money
}
// 实现 父抽象类的方法
run(): void {
}
// 实现 父抽象类的方法
back: () => void = () => {
}
}
const s1 = new Student(1000)
19. 接口
接口的单继承,多继承,使用类实现接口
// 接口 interface
/**
* 接口是抽象类中的特殊种族 这里面所有的属性和方法都只有声明,没有实现
*/
interface Person {
name: string
run: () => void
back(): void
}
interface Phone {
brand: string
}
// 接口的单继承
interface Parent extends Person {
money: number
}
// 接口的多继承
interface Stuent extends Person, Phone {
school: string
}
// 使用类 来实现接口
class Father implements Parent {
name: string
money: number
constructor(name: string, money: number) {
this.name = name
this.money = money
}
run(): void {
}
back(): void {
}
}
const f1 = new Father('zrs', 10000)
20. 多态
// 多态
/**
* 多态就是将接口预留好,后面直接写代码实现,然后调用
*/
interface USB {
start(): void
run(): void
end(): void
}
function demo(u: USB) {
u.start()
u.run()
u.end()
}
class ShuBiao implements USB {
start(): void {
console.log("开启");
}
run(): void {
console.log("正常运行");
}
end(): void {
console.log("结束");
}
}
demo(new ShuBiao())
21. 接口的灵活运用
// 使用别名不能声明重名的
type obj={
name:string,
age:number
}
// type obj={} // 报错
const o1:obj={
name:'zrs',
age:12
}
// 重名的接口会合并
interface obj1{
name:string
}
interface obj1{
age:number
}
const o2:obj1={
name:'zrss',
age:10
}
// 以上方式都限制了 实例化之后的属性的个数,下面这种方式将不会限制属性的个数
interface obj2{
[index:number]:string
}
// 对象里可以添加任意多个符合要求的属性和属性值
const o3:obj2={
1:'姓名',
2:'性别'
}
// 对象里可以添加任意多个符合要求的属性和属性值
interface obj3{
[key:string]:string
}
const o4:obj3={
name:'zzr',
age:'12'
}
22. 泛型
/**
* 泛型,就是在定义的时候不指定类型,在使用的时候指定类型
*/
/**
* 泛型参数化
*/
function fun<T>(a:T,b:T):T {
console.log(a,b)
return a
}
// 在使用的时候指定类型
fun<number>(10,11)
fun<string>('asd','wer')
// 在声明的时候也可以指定多个泛型
function fun2<A,S,D>(a:A,b:S,c:D) {
console.log(a,b,c)
}
// 调用的时候指定类型
fun2<number,string,boolean>(1,'qwert',true)
/**
* 泛型的默认值
*/
// T=number 就是泛型的默认值
function fun3<T=number>(args:T){
console.log(args)
}
fun3(11)
fun3<string>('sdf')
/**
* 类型的约束
*/
interface ILength{
length:number
}
// 让这个泛型 去继承 接口 保证传入的值有一个length属性
function func4<T extends ILength>(args:T){
console.log("func4",args.length)
}
func4('abc')
func4([1,2,3,4])
func4({name:'zrs',length:123})
/**
* 泛型的接口
*/
interface IPerson<T1=string,T2=number>{
name:T1,
age:T2
}
// 使用泛型的默认值
const p1:IPerson={
name:'zrs',
age:12
}
// 指定泛型的类型
const p2:IPerson<string,string>={
name:'zrs',
age:'12'
}
// 创建泛型的类
class Person<T1,T2> {
name:T1
age:T2
sex:T1
constructor(name:T1,age:T2,sex:T1) {
this.name=name
this.age=age
this.sex=sex
}
}
// 实例化的第一种方式 让其自行推断
const p5=new Person('asd',12,'male')
// 实例化的第二种方式
const p6=new Person<string,number>('asdf',122,'male')
// 实例化的第三种方式
const p7:Person<string,number>=new Person('asd',1,'male')
// 第三种方式类似于数组的泛型声明
const arr:Array<number>=[]
23. ts中的命名空间
// 命名空间
// demo2.ts 文件
// 跨文件的命名空间也需要导出 才可以使用
export namespace login{
export function fun(flag:boolean){
if(flag){
console.log("登录成功")
}else{
console.log("登录失败")
}
}
}
// demo1.ts 文件
/**
* 命名空间
*/
import {login} from './demo2'
// 命名空间是为了解决命名冲突的问题
namespace uname{
// 命名空间中函数,变量 都需要 使用 export 导出才可以在外面使用
export function fun<T1>(args:T1){
console.log(args)
}
export const PI:number=3.1415926
}
namespace product{
export function fun(args:number){
console.log(args)
}
// 注意: 嵌套的命名空间也需要导出
export namespace list{
export let name:string='zrs'
}
}
// 使用命名空间之内的函数,变量
uname.fun<number>(12313213)
product.fun(9876)
console.log(uname.PI)
// 调用嵌套的命名空间
console.log(product.list.name)
// 多个文件的命名空间使用 需要先导入文件
login.fun(false)