目录
一、泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。。
1、 函数泛型
<T>表示定义模板类型,(arg: T): T 表示参数和返回值类型都是同一个类型,
具体T是什么类型就实参决定
function a<T>(arg: T): T {
return arg;
}
let r1 = a(100);//T的类型是number
let r2 = a("小王");//T的类型是string
console.log(r1, r2);
匿名函数和箭头函数泛型语法
//匿名函数
let a = function <T>(arg: T): T {
return arg;
}
//箭头函数
let a = <T>(arg: T):T =>{
return arg;
}
我们来实现一个函数 createArray,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值:
function createArray<T123>(len: number, value: T123): T123[] {
let arr: any[] = [];
for (let j: number = 0; j < len; j++) {
arr.push(value);
}
return arr;
}
console.log(createArray<string>(5, 'h'));
console.log(createArray(5, 0o700));
interface dataType {
id: number;
title: string;
cover: string;
tags: string[]
}
console.log(createArray<dataType>(5, {
id: 23,
title: '今天星期天',
cover: 'http:///7001.png',
tags: ['创意', '星期天', '线上']
}));
2 模板类型可以是多个
function a<T1, T2>(a:string, b:T1, c:T2): T2 {
return c;
}
a("纟", 100, true)
function a<T1, T2>(a:string, b:T1, c:T2): string {
return "小王";
}
let a = function<T1, T2>(a:string, b:T1, c:T2): T2 {
return c;
}
let a = <T1, T2>(a:string, b:T1, c:T2): T2 => {
return c;
}
function change<T1, T2>(tuple: [T1, T2]): [T2, T1] {
3 泛型的错误
function a(a:T1, b:T2): T1 {
let r = a + b;//编译报错,因为编译器不知道T1和T2是什么类型,所以不确定是否能进行 + 运算
return r;
}
let r = a("小王", 100);
console.log(r);
function a(a:T1): T1 {
return a+100;//编译报错,因为编译器不知道T1是什么类型,所以不确定是否能进行 + 100
}
function loggingIdentity(arg: T): T {
console.log(arg.length) //编译报错,因为编译器不知道T1是什么类型,所以不确定是否有属性length
return arg
}
4 泛型函数变量
> 函数的变量类型也可以使用泛型
function identity<T>(arg: T): T {
return arg;
}
interface IM {
<x>(arg: x):x
}
let x:IM = identity;//
let myIdentity1: <U>(arg:U)=>U = identity;
let myIdentity2: {<U>(arg:U):U} = identity;
5 泛型函数类型接口
> (1)泛型函数类型接口1
function identity<T>(arg: T): T {
console.log("identity")
return arg;
}
//泛型函数类型接口1, 其中的T可以改为其它自定我,不必与函数中T相同
interface GenericIdentityFn1 {
<T>(arg: T): T;
}
//值也必须是有泛型的函数
let myIdentity: GenericIdentityFn1 = identity;
//<string>决定了参数只能使用string
myIdentity<string>("sddssd");
//<number>决定了参数只能使用number
myIdentity<number>(234);
(2)泛型类函数型接口2
//泛型类函数型接口2
interface GenericIdentityFn2<T> {
(arg: T): T;
}
//<number>决定了参数只能使用number
let myIdentity2: GenericIdentityFn2<number> = identity;
myIdentity2(234);
//<string>决定了参数只能使用string
let myIdentity3: GenericIdentityFn2<string> = identity;
myIdentity3("小王");
console.log(r);
6 泛型类1
(1)新new出对象是{ },其中无成员
(2)对象中只能全部或部分实现类中声明好的成员,不能增加其它成员
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
// 或 yGenericNumber.add = function(x:number, y:number) { return x + y; };
let r = myGenericNumber.add(1, 22);
console.log(r);
//myGenericNumber.sex = ‘男’; 错,因为类中没有声明sex
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "fds";
stringNumeric.add = function(x, y) { return x + y; };
let r2 = stringNumeric.add("1", "22");
console.log(r2);
7 泛型类2
new出的对象已经具体类中的成员
class A<T> {
a:T;
show(a:T, b:T) {
console.log(a, b);
}
}
let a1 = new A<string>();
a1.show("fsd","fsd")
let a2 = new A<number>();
a2.show(123,444)
let p2:A<string>;
p2=new A<string>()
p2.show("hello","ts")
//下面代码也不会报错,T不生效
let a3 = new A();
a3.show(444,"555");
8 泛型约束
在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法.
> <T extends IA> 要求T类型数据至少有IA中声明的成员
interface IA {
length: number;
}
//要求T类型数据有length属性
function m1<T extends IA>(arg: T): T {
console.log(arg.length);
return arg;
}
let r;
r = m1("小王");//"小王"有length属性
console.log(r);//2
r = m1({length: 10, value: 3});//{length: 10, value: 3}有length属性
console.log(r);//10
interface IA {
length: number;
value: number;
}
//要求T有属性length和value
function m1<T extends IA>(arg: T): T {
console.log(arg.length, arg.value);
return arg;
}
m1({length: 10, value: 3, age:30});
以上泛型约束示例仅仅是函数中使用,实计上也可以使用于其它使用泛型的地方,看看下面的示例吧
class Person {
name:string;
sex:string;
constructor(name, sex) {
this.name = name;
this.sex = sex;
}
show() {
console.log(this.name, this.sex);
}
}
class Stu<T> {
show(p:T) {
console.log(p);
p.show();//有错
}
}
let stu = new Stu<Person>();
let p = new Person("小王", '男');
stu.show(p);
以下示例有一个问题,p.show()会出错, 如果改为下面的泛型约束就可以解决该类问题
class Person {
name:string;
sex:string;
constructor(name, sex) {
this.name = name;
this.sex = sex;
}
show() {
console.log(this.name, this.sex);
}
}
class Stu<T extends Person> {
show(p:T) {
console.log(p);
p.show();
}
}
let stu = new Stu<Person>();
stu.show()
let p = new Person("小王", '男');
stu.show(p);
**多个类型参数之间也可以互相约束**:
function copyObj<T extends U, U>(target: T, source: U): T {
for (const k in source) {
target[k] = (<T>source)[k];
}
return target;
}
let x123 = {a:1, b:2, c:3};
const source1 = {a:1, b:2, c:3};
copyObj(x123, source1);
console.log(x123);
9 泛型参数的默认类型
我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用。
function createArray<T = string>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
二、声明文件
当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
假如我们想使用第三方库 jQuery,一种常见的方式是在 html 中通过 <script> 标签引入 jQuery,然后就可以使用全局变量 $ 或 jQuery 了。
我们通常这样获取一个 id 是 foo 的元素:
$('#foo');
// or
jQuery('#foo');但是在 ts 中,编译器并不知道 $ 或 jQuery 是什么东西:
jQuery('#foo');
// ERROR: Cannot find name 'jQuery'.这时,我们需要使用 declare var 来定义它的类型
declare var jQuery: (selector: string) => any;
jQuery('#foo');
什么是声明文件
通常我们会把声明语句放到一个单独的文件(jQuery.d.ts)中,这就是声明文件
**声明文件必须以 .d.ts 为后缀**
// src/jQuery.d.ts
declare var jQuery: (selector: string) => any;
// src/index.ts
jQuery('#foo');
第三方声明文件
jQuery 的声明文件不需要我们定义了,社区已经帮我们定义好了
我们可以直接下载下来使用,但是更推荐的是使用 @types 统一管理第三方库的声明文件。
@types 的使用方式很简单,直接用 npm 安装对应的声明模块即可,以 jQuery 举例
npm install @types/jquery --save-dev
三、Vue3.0集成ts
Vue写ts语言,不用关心转换语法问题,脚手架已经集成了ts-loader,进行转换
1、项目文件夹 -> cmd -> npm init vite +app(项目名字)
2、选择:vue ts 然后 cd app npm