Typescript的学习笔记
前置准备
- nodejs必安装
- 全局安装
typescript
1 | npm install typescript -g |
使用
tsc
命令对ts文件进行编译- 进入命名行
- 进入ts文件所在目录
- 执行命名
tsc xxx.ts
即可,xxx.ts中xxx为文件名- 如果没有在报错的情况下进行编译,默认情况下依旧会进行编译,但是可以后期配置不编译
- 编译可以编译为任意js(兼容性处理更加好),后期可以通过配置文件进行配置
文章很多参考和学习这位博主的
ts的基本类型
类型声明是TS非常重要的一个特点
通过类型声明可以指定TS中变量(参数、形参)的类型
指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错
简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值
ts一些类型
类型 | 例子 | 描述 |
---|---|---|
number | 1, -33, 2.5 | 任意数字 |
string | ‘hi’, “hi”, hi | 任意字符串 |
boolean | true、false | 布尔值true或false |
字面量 | 其本身 | 限制变量的值就是该字面量的值 |
any | * | 任意类型 |
unknown | * | 类型安全的any |
void | 空值(undefined) | 没有值(或undefined) |
never | 没有值 | 不能是任何值 |
object | {name:’孙悟空’} | 任意的JS对象 |
array | [1,2,3] | 任意JS数组 |
tuple | [4,5] | 元组,TS新增类型,固定长度数组 |
enum | enum{A, B} | 枚举,TS中新增类型 |
… | … | … |
类型声明细节
类型声明(手动)
1 | //手动指明类型 |
类型声明(自动)
- 变量的声明和赋值是同时进行的,ts就可以自动对变量进行类型检测的
1 | //ts会自动指明类型 |
示例
1 | // 变量的声明和赋值是同时进行 |
类型声明特殊情况-使用字面量
- 使用字面量去指定变量的类型,通过字面量可以确定变量的取值范围
1 | let zml:10; |
ts的其他类型说明
number
这个不多说声明
支持进制表示
示例代码
1 | let decimal: number = 6; |
boolean
- 示例代码
1 | let isDone: boolean = false; |
string
示例代码
1
2
3
4
5
6
7
8let color: string = "blue";
color = 'red';
let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${fullName}.
I'll be ${age + 1} years old next month.`;
any
使用any任意类型,相当于对该变量关闭了ts的类型检测,和普通的js代码一样了
- 示例代码;
1 | //声明的时候指明类型,显式的any |
unknown
示例代码
1
2
3
4
5let notSure: unknown = 4;
notSure = 'hello';
let str:string = '123';
// str = notSure;//发生报错,unknown不会祸害其他为什么要使用unknown
第一个原因就是
any
会祸害其他变量,导致any
类型的可以和任何变量兼容,而unknown
却做不到第二个原因就是TypeScript 不允许使用
unknown
的变量,除非将该变量强制转换为已知类型或收窄其类型。(这样子就很好的对变量起到了一个类型的判断)1
2
3
4
5
6
7
8
9
10
11
12
13
14const x: unknown = 1;
x*x;//报错 提示对象的类型为 "unknown"
if(typeof x === 'number'){
//将该变量强制转换为已知类型或收窄其类型
//不报错
console.log(x*x);
//不报错
console.log(<number>x * <number>x);
}
const x:any = 1;
x*x;//不会报错
void
表示没有返回值
示例代码
1
2
3
4
5
6let unusable: void = undefined;
//void类型
function fn1():void{
console.log("123");
}
never
表示永远不会返回结果,比如这个函数是用来报错的,所以永远不会返回结果
示例代码
1
2
3function error(message: string): never {
throw new Error(message);
}
object
不过这种object类型不太经常用,因为很多情况下都是object
比如
typeof null
返回值是object并且ts认为函数也是一个object
示例代码
1
let obj: object = {};
{}
- 用来指定对象中可以包含哪些属性,并且结构要一模一样,多了,少了都不可以!
- 比如
let b: {name:string}
//设定指向一个对象,并且有name属性,并且name属性为string - 属性名后面加一个问号,表示这个属性是可选的
1 | //sex为可选 |
[propName:string]:any
表示任意类型的属性值- propName名字可以随便的,这里只是为了区分下,也可以
[xxxx:string]:any
- 当然,如果需要指明value的类型,可以把any改为指定的类型,比如
[propName:string]:string
表示value要为string类型
1
2
3
4
5//表示有必须要有key为name,value类型为string的值,和其他任意数量的任意key(类型必须要为string)和value(类型随意)
let myObj: { name: string, [propName: string]: any }
myObj = { 'name': '李白', "sex": '男' };
myObj = { 'name': '李白', "sex": '男', 'hobby': "吃饭" };//不报错
myObj = { 'name': '李白', "sex": '男', 'hobby': 555 };//不报错- propName名字可以随便的,这里只是为了区分下,也可以
设置函数结构的类型声明
- 语法: (形参1:类型1 , 形参2:类型2 [,…] ) => 返回值
- 比如 希望
getSum
为函数,并且有二个参数,均为number,并且返回值为number
1 | function getSum(a: number, b: number): number { |
- 希望
getResult
为函数,并且有二个参数,一个为object
,另一个为string
,并且返回值为number
或者string
1 | function getResult(a: object, b: string): number | string { |
array(数组)
之前的数组的什么都可以存的,在ts当中可以设置存储数据的类型
格式
类型[]
- 比如
let typeNumberArray:number[]
;创建一个全部类型都是number
的数组
- 比如
Array<类型>
(数组泛型的表示)- 比如
let typeNumberArray:Array<number>;
创建一个全部类型都是number
的数组
- 比如
示例代码
1
2
3
4
5
6
7
8
9//表示数组里面只可以存储number类型
let typeNumberArray:number[];
let typeNumberArray:Array<number>;
typeNumberArray = [1,2,3];
// typeNumberArray = [1,2,'3'];//报错
let a:string[];//代表字符串数组
let b:number[];//代表数字数组需要注意的是,数组的一些方法,比如说
push
也会受到约束
1 | let myArray:number[] = [1,2,3,4,56]; |
tuple(元组)
元组就是固定长度的数组,里面存储的值多了不可以,少了也不可以
和数组的类型声明不用的就是反转了下,现在
[]
在前面了,类型在后面了示例代码
1
2
3
4
5
6
7let x: [string, number];
x = ["hello", 10];
let h: [string, string];
h = ['123', '456'];
h = ['123'];//少了,报错;
h = ['123', '456', '689'];//多了,报错
enum(枚举)
示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13enum Sex {
Male,
Female
}
//设置一个数组的结构为userName和sex
let userInfo: { userName: string, sex: Sex };
userInfo = {
userName:"李白",
//使用枚举
sex:Sex.Male
}上面代码编译后的js代码
1 | var Sex; |
&(表示同时满足条件)
1 | //表示key当中既要有name属性和age属性,并且符合规定的value类型 |
|(联合类型)
- 通过
|
来分割类型,从而使得某一个变量类型可以为多个- 比如如下示例
let unionType:string|number;
代表的意思就是unionType
类型可以为string
,也可以为number
,但是不能为其他类型
- 比如如下示例
1 | let unionType:string|number; |
type(类型别名)
- 关键字是
type
1 | type myType = 1 | 2 | 3 | 4 | 5 | 6; |
类型断言
有时候二边类型编译器判断是不同,但是我们已经明确知道了二边类型是一样的,这时候就可以使用类型断言
语法 变量 as 类型 或者 <类型>变量
比如: 如果直接将unknown赋值给其他类型的变量,是会发生报错的,所以我们需要类型断言
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20let notSure: unknown = 'biubiu';
let strType = '123';
//不进行断言,会报错
// strType = notSure;
//进行类型断言
strType = notSure as string;
//或者这种形式的类型断言
strType = <string> notSure;
//类型断言
function getLength2(str:number|string):number{
// return (str as string).length;
// 或者
return (<string>str).length;
}
非空断言
- 相当与是多加了一层判断,存在才会执行下去
1 | // 非空断言 |
- 添加了
非空断言
(相当与是return arg && arg.length
)
1 | // 非空断言 |
ts编译
自动编译(单个文件编译,无需配置文件)
- 编译文件的时候,使用
-w
指令后,ts编译器会自动监视文件的变化,并在文件发生变化时候对文件进行重新编译 - 示例:
tsc xxx.ts -w
- 缺点: 只能对一个文件进行ts,因为没有配置文件!
自动编译(整个编译,有配置文件)
配置文件名称为
tsconfig.json
tsconfig.json
是一个JSON文件,里面填写配置文件项注意:
tsconfig.json
是可以添加注释的~其他的JSON不可以哦tsconfig.json配置对象如下,官网API
1.include
- 设置希望被编译文件所在的目录,为一个数组
- 默认值为:
["**/*"]
代表当前命名行下所有文件夹和文件
示例:
1 | { |
了解下 **
和 *
在tsconfig.json的作用
**/
递归匹配任意子目录*
表示匹配任意文件
2.exclude
- 设置排除列表
- 默认值:
["node_modules", "bower_components", "jspm_packages"]
示例:
1 | { |
3.files
- 指定被编译文件的列表,只有需要编译的文件少时才会用到
示例: 列表中的文件都会被ts编译器所编译
1 | { |
4.extends
- 继承配置文件
- 具体可看官网
示例:
1 | { |
5.compilerOptions(重要)
- 编译器的选项,比如说编译模式之类的,里面是由
key
和value
组成的 - 下面为常见的key
1.taget
- 用来指明ts被编译为js的版本,默认值为”es3”
- 可选值为:
'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'es2021', 'esnext'.
target设置为es6的效果
1 | //编译前 //编译后 |
2.module
- 指明要使用的模块化规范
- 可选值为:
'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'es2022', 'esnext', 'node12', 'nodenext'
实例如图: 设置模块化规范为commonjs
index.ts
使用es6模块化规范导出say
函数,app.ts
引入say函数并输出
,然后查看编译后的app.js
3.outDir
- 指定编译后的js文件所在目录
- 默认情况下,编译后的js文件会和ts文件位于相同的目录,设置
outDir
后可以改变编译后文件的位置
示例:
1 | { |
4.outFile
- 将所有的文件编译为一个js文件,默认会将所有编写在全局作用域下的代码合并为一个js文件
- 如果
module
配置项指定了none
,style
或者amd
,则会将模块一起合并到文件之中,这几个才可以,es6
不可以
5.lib
- 指明要使用的库
- 可以写的值
1 | 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'es2021', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2020.bigint', 'es2020.promise', 'es2020.sharedmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'es2021.promise', 'es2021.string', 'es2021.weakref', 'es2021.intl', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise', 'esnext.weakref'. |
6.allowJs
- 是否对js文件进行编译,因为当前目录不止会有ts,可能还有js文件
- 默认为
false
,代表不编译js - 为true代表编译,为false代表不编译js
7.checkJs
- 是否对js文件进行检查
- 默认为
false
,代表不检查
8.removeComments
- 是否移除注释
- 默认为
false
代表不移除
9.noEmit
- 不生成编译后的文件
- 默认为
false
,代表生成编译后的文件 - 一般用在只想用ts进行语法检查的情况下使用这个配置项
10.noEmitOnError
- 当有错误的时候不生成编译后的文件
- 默认为
false
,代表ts文件有报错也生成js文件,所以我们经常可以看到有报错还编译生成了js文件就是这个原因
严格检查系列
11.strict(总开关)
- 开启了这个,下面所有的配置项都会设置为true,默认值为false
12.alwaysStrict
总是以严格模式对代码进行编译
注意:如果使用了es6模块化,那么就自动开启了严格模式,所以编译后不会添加”use strict”关键字
值可以为 true | false
13.noImplicitAny
- 禁止隐式的any类型,默认为
false
- 设置为
true
后,隐式的any类型不被允许
14.noImplicitThis
- 禁止类型不明确的this
如图 所以要指明this的类型 测试了.断言是不可以的忽略这语句的
忽略错误
- 比如根据id获取,可能会获取不到,但是已经确认了 后面加一个 !
- var a = document.getElementById(“food”)!;
- 或者直接
@ts-ignore
忽略当前行错误
其他的一些忽略
1 | 忽略全文 |
ts-node(编译运行ts代码)
安装:
1 | npm install ts-node -g |
使用: xxx.ts为文件名称
ts-node xxx.ts
interface(接口)
- 接口,我理解为就是一个数据类型,和
number,undefined,string等
类似
简单的例子
1 | interface Person{ |
可选属性
- 有时我们希望不要完全匹配一个形状,那么可以用可选属性
- 可选属性的含义是该属性可以不存在
1 | interface Person { |
- 这时仍然不允许添加未定义的属性:
1 | interface Person { |
任意属性
- 有时候我们希望一个接口允许有任意的属性,可以使用如下方式:
- 任意属性就是属性名不固定,属性值类型也是不固定
1 | interface Person { |
- 需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集:
1 | //如此示例 |
- 上例中,任意属性的值允许是
string
,但是可选属性age
的值却是number
,number
不是string
的子属性,所以报错了。 - 另外,在报错信息中可以看出,此时
{ name: 'Tom', age: 25, gender: 'male' }
的类型被推断成了{ [x: string]: string | number; name: string; age: number; gender: string; }
,这是联合类型和接口的结合。 - 一个接口中只能定义一个任意属性。如果接口中有多个类型的属性,则可以在任意属性中使用联合类型:
1 | interface Person { |
只读属性
- 有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用
readonly
定义只读属性:
1 | interface Person { |
接口表示数组
- 接口也可以用来描述数组:
- 注意
- 这里的
[index:number]:number;
当中的index
和之前的propName
一样,可以自定义名称,这里为了便于区分就命名为index
- 代表的意思就是:当key为
number
的时候,所对应的value必须要为number
类型
- 这里的
- 回想下
- 回想下在之前写到过的
[propName: string]: any }
,代表的就是任意的对象属性 - 代表的意思就是:当key为
string
类型的时候,所对应的value必须要为number
类型
- 回想下在之前写到过的
1 | interface numberList { |
接口表示一个含函数的对象
1 | interface computed { |
函数
- 函数-分为函数的声明,和函数的表达式
- 函数的声明:函数声明,和
var
类型的变量一样,会把代码提示到最前面定义(变量提升和函数提升) - 函数的表达式:函数在代码执行的时候才会被执行
- 函数的声明:函数声明,和
1 | // 函数声明(Function Declaration) |
函数的声明
- 需要注意的是,函数在typescript当中,声明/定义的时候,参数有几个,使用的时候就应该传入几个,多或者少都不可以
1 | function sum(x: number, y: number): number { |
函数的表达式
- 注意不要混淆了 TypeScript 中的
=>
和 ES6 中的=>
。 在 TypeScript 的类型定义中,=>
用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。 变量类型(var或则const或者let) 接收的变量名:(参数)=>返回值类型 = 函数表达式
1 | const getSum1 = function sum(x: number, y: number): number { |
鼠标放在getSum1
和getSum2
上面,编译器都可以推断出来有什么参数和返回值类型
用接口定义函数的形状
- 和
对象
,数组
接口的区别就是有一个小括号,并且小括号里面可以写多个变量名和类型,并用逗号分割 - 如下例子
1 | // 回想,之前定义变量的接口是怎么定义的 |
剩余参数
- es6中,可以使用
...rest
的方式获取函数中的剩余参数
1 | function push(array, ...items) { |
- 事实上,
items
是一个数组。所以我们可以用数组的类型来定义它:- 注意,rest 参数只能是最后一个参数,关于 rest 参数,可以参考 ES6 中的 rest 参数。
1 | function push(array:any[],...items:any[]){ |
泛型
那么什么是泛型呢?
- 泛型就是值在定义函数,接口,类的时候,不预先指定具体的类型,而是在使用的时候才去指定类型
- 简单来说就是我现在不去规定你这一个变量的具体类型,而是在使用的时候动态去指明(橡皮泥一样)
如果没有泛型,想一想接收一个什么样子类型的参数,就返回什么类型的参数要怎么做,做法就是如下,一个一个写出来
1 | /* 返回一个number类型的数据,也就是输入number,返回number */ |
- 但是如果有了
泛型
,就不用这样子了,我们直接在函数后面添加<T>
,然后其他类型改为<T>
即可实现泛型- 这样子就可以做到上面所说的接收什么类型,就返回什么类型的参数
1 | function returnValue<T>(value1:T):T{ |
- 再来看看下面案例,我们在函数名的后面添加了
<T>
,其中T
代表任意输入的类型,在后面的输入value:T
和输出Array<T>
中即可使用了
1 | function createArray<T>(length:number,value:T):Array<T>{ |
多个类型参数
- 下列函数的功能就是定义一个函数,传入一个二个值的函数,可以交换这二个值
- 其实你仔细看也不是很复杂,就是类型的定义,
changValue
后面的<T,U>
代表会接收二种未指明类型的数据,分别用T
和U
来表示tuple:[T,U]
代表是含有二个值的元组(元组就是固定长度的数组)- 函数最后面的
:[U,T]
代表返回值为一个元组,并且类型要是先U
类型,然后在T
类型
1 | function changeValue<T,U>(tuple:[T,U]):[U,T]{ |
泛型约束
在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法,使用就需要泛型约束
泛型约束,大白话说就是规定泛型的内容,必须要符合我们规定的才可以
关键字是
extends
和接口的使用下面这个案例当中,泛型
T
不一定包含属性length
,所以编译的时候报错了。
1 | function charge<T>(arg:T):T{ |
- 这时,我们可以对泛型进行约束,只允许这个函数传入那些包含
length
属性的变量。这就是泛型约束:- 下面案例当中,我们约束了泛型
T
的范围,使其必须要符合接口lengthWise
的形状,也就是必须要包含length
属性 - 这里调用
charge("李白")
不会报错,是因为"李白"
本身是含有length
属性的,并且也满足我规定的length
属性为number
类型
- 下面案例当中,我们约束了泛型
1 | interface lengthWise { |
- 此时如果调用
loggingIdentity
的时候,传入的arg
不包含length
,那么在编译阶段就会报错了
1 | interface lengthWise { |
内置对象
- @参考文章 - 写的很好
- 最好了解了解内置对象,不然你就会出现如下问题
- 我通过
document.querySelectorAll()
获取dom元素,但是返回的变量类型是什么啊?我应该给接收这个变量规定什么类型啊? - ……
- 我通过
ECMAScript 的内置对象
1 | let b:Boolean = new Boolean(1); |
更多的内置对象,可以查看 MDN 的文档。
而他们的定义文件,则在 TypeScript 核心库的定义文件中。
DOM 和 BOM 的内置对象
TypeScript 中会经常用到这些类型:
1 | let body:HTMLElement = document.body; |
class类
- 其实我们一些类的思想已经有了,比如
- 操作浏览器要使用window对象
- 比如网页的前进后退
- 操作网页要使用document对象
- 比如操作网页的dom元素
- 操作控制台要使用console对象
- 比如输出错误,输出警告
- 操作浏览器要使用window对象
- ts当中的的类是作为一种类型存在的
如图,演示了一种Person
类型,一种string
类型
类的实例属性
- 实例属性,就是实例化对象的属性,每一个实例对象当中的实例属性都是独立的
- 声明实例属性的时候,既可以赋予初始值,也可以后期通过
constructor
函数来赋初始值
1 | class Person { |
类的构造函数
- 构造函数,就是为实例属性赋予初始值的一个函数!
- 注意,构造函数当中不需要返回值和返回值类型!
- 注意,如果没有在
constructor
上方注明实例属性,那么输入代码的时候可能会没有提示
正确的(含有实例属性)
1 | class Person { |
错误的,没有声明实例属性
- 在
constructor
当中,this执行的是新创建的实例对象 - 所以
this.age
访问的是实例属性,所以这里提示类型Person上不存在属性age
1 | class Person { |
没有声明实例属性的报错提示
类的继承
extends(js,ts都有)
- 不多说,看代码~关键字
extends
,记得调用super
去调用父类的构造函数
1 | //父类 |
可见性修饰符(用于属性或方法)
public
- 公有:默认值,所有的成员都可以在任何地方访问,不管是继承后的子类,还是自己,都可以
- 没有说明可见性修饰符则默认是
public
protected
- 保护: 只可以在其声明所在类和子类当中使用(实例化对象不可用)
示例代码: 设置叫声为私有属性
1 | //父类 |
报错提示
修饰符用于方法
private
- 私有:只可以在其声明所在类中使用,其他都不可以使用
示例代码
1 | class Person{ |
readonly修饰符(只可用于属性)
readonly表示只读,用来防止在构造函数之外对属性进制赋值!!!
使用readonly关键字修饰该属性是只读的,注意只能修饰属性不能修饰方法。
接口或者 {} 表示的对象类型,也可以使用readonly
只要是readonly来修饰的属性,必须手动提供明确的类型,否者就成为了一个字面量!
示例代码:
1 | class Person { |
示例代码:用于{}
1 | let obj: { readonly name: string } = { name: 'jack' }; |
接口(interface)
- 接口的作用类似于抽象类,不同点在于接口中的所有方法和属性都是没有实值的,换句话说接口中的所有方法都是抽象方法。接口主要负责定义一个类的结构,接口可以去限制一个对象的接口,对象只有包含接口中定义的所有属性和方法时才能匹配接口。同时,可以让一个类去实现接口,实现接口时类中要保护接口中的所有属性。
- 可以使用接口对对象进行约束
- 也可以使用接口对类进行约束
示例:使用接口对对象进行约束
1 | interface Person { |
示例:使用接口对类进行约束(接口的实现)
1 | interface Person { |
示例1:接口的实现
1 | // 接口的实现 |
抽象类/抽象方法
- 抽象类是专门用来被其他类所继承的类,它只能被其他类所继承不能用来创建实例
- 抽象类中可以有抽象方法和普通方法
- 抽象方法只能定义在抽象类当中
- 子类必须要对抽象类的抽象方法进行重写
示例
1 | abstract class Animals { |
泛型(Generic)
定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确定),此时泛型便能够发挥作用。
格式,在括号前面添加
<>
比如一个函数,我要求有一个参数,用户传入这个参数的类型就是这个函数返回值的类型,那要怎么做?使用泛型
不推荐使用any!
1 | //!不推荐使用any! |
使用泛型
- 这里的
<T>
就是泛型,T是我们给这个类型起的名字(不一定非叫T),设置泛型后即可在函数中使用T来表示该类型。所以泛型其实很好理解,就表示某个类型。
1 | function test<T>(arg: T) { |
那么如何使用泛型定义的函数?
- 方式一:直接使用
- 使用时可以直接传递参数使用,类型会由TS自动推断出来,但有时编译器无法自动推断时还需要使用下面的方式
1 | function test<T>(arg: T) { |
- 方式二:指明类型
1 | function test<T>(arg: T) { |
- 可以同时指定多个泛型,泛型间使用逗号隔开:
1 | function test2<T, K>(arg1: T, arg2: K): K { |
- 类中同样可以使用泛型:
1 | class MyClass<T>{ |
- 除此之外,也可以对泛型的范围进行约束
使用T extends MyInter
表示泛型T必须是MyInter的子类,不一定非要使用接口类和抽象类同样适用。
1 | interface MyInter{ |
其他
函数默认值
1 | // 设置name 默认值为'李白' age为'18' |