TypeScript学习笔记

1、安装TypeScript

npm install -g typescript//安装
tsc -v//查看安装版本
tsc (要编译的文件)//将ts文件转换为js文件
node (被编译js文件)//执行文件

2、tsc编译

tsc (要编译的文件名)

编译完的js文件不存在变量类型

ts; //编译前
let test: number = 18;
js; //编译后
var test = 18;

3、安装ts-node包

npm install -g ts-node//安装
ts-node (ts文件名)//运行文件

4、TS常用类型

TypeScript是js的超集,TS提供了JS的所有功能,并且额外的增加了:类型系统。

注:JS不会检查变量的类型是否发生变化,而TS会检查

4.1、类型注解

let test: number = 18; //类型注解

4.2、常用基础类型

可以将TS中的常用基础类型细分为两类

  1. JS原有类型

原始类型:number/string /boolearn/null/undefind/symbol

let test: number = 18; //数字类型
let test1: string = '18'; //字符串类型
let test2: boolean = true; //布尔类型
let test3: null = null; //空
let test4: undefined = undefined; //undefinf类型
let test5: symbol = Symbol(); //symbol类型

对象类型:object(包括数组、对象、函数对象)

数组:

let test: number[] = [1, 2, 3]; // (推荐)
let test: Array<string> = ['a', 'b', 'c'];
let test: (number | string)[] = [1, 'k', 'c', 5]; //(数组中有多种类型)
  1. TS新增类型

联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any等

4.3、联合类型

let Test: number | string; //number或string

4.4、类型别名

简述:为任意类型起名

关键字:type

用途:一种复杂类型被多次使用时可以通过类型别名替换使用。例如

type CustomArray = (number | string)[];
let text: CustomArray = [1, 'v', 'c', 5];

4.5、函数类型

函数类型就是为函数的参数和返回值添加类型

为函数指定类型方式有两种

1.单独指定参数、返回值类型

function test(num1: number, num2: number): number {  //普通函数
  return num1 + num2;
}
const test = (num1: number, num2: number): number => {  //箭头函数
  return num1 + num2;
};

2、同时指定指定参数、返回值类型

const test: (num1: number, num2: number) => number = (num1, num2) => {  //指定
  return num1 + num2;
};

注:这种方式只适用于函数表达式

void类型

function test(name: string): void {  //没有返回值的函数为void类型
  console.log(name);
}

传递可选参数

function test(num?: number): void {  //可选参数就是在参数的后面+?
  console.log(num);
}

4.6、对象类型

JS中的对象是由属性和方法构成的,而TS的对象实在描述对象的机构

写法:

let test: { name: string; age: number; play(): void; playl(item: number): void } = {
  name: 'lisi',
  age: 15,
  play() {},
  playl(item: 1) {},
};

竖排情况下可以去掉分号

let test: {
  name: string;
  age: number;
  play(): void;
  playl(item: number): void;
} = {
  name: 'lisi',
  age: 15,
  play() {},
  playl(item: 1) {},
};

对象作为参数传递时属性也可以实现选择传输

function test(obj: { name: string; age?: number }): void {  //对象的属性实现可选同样+?
  console.log(obj);
}

4.7、接口

使用interface关键字声明接口(只用于声明属性一起属性类型)

interface Test {  //声明接口
  name: string;
  age: number;
  play(): void;
}

使用时只需要调用接口

let test: Test = {
  name: 'lisi',
  age: 15,
  play() {},
};

注:接口只能为对象声明变量类型(前面学到的type类型别名 可以对多种类型指定类型

如果两个接口之间有相同的属性或方法,可以将公共得到属性抽离出来,通过继承来实现复用,关键字(extends)

interface Test1 {
  name: string;
}
interface Test2 {
  name: string;
  age: number;
}

两者的效果一样

interface Test1 {
  name: string;
}
interface Test2 extends Test1 {
  age: number;
}

4.8、元组

使用场景:在地图中标注使用经纬度标注信息(以及确切的知道包含多少元素,以及特定索引对应的类型)

可以用数组来标注,数组中只有两个元素,并且都是数值类型

let test: number[] = [32.25211, 12.5665]; //可以但是不推荐(数组中可能会出现多个元素)
let test: [number, number] = [32.25211, 12.5665]; //推荐

4.9、类型推论

在TS中某些没有明确指出类型的地方,ts的类型推论机制会帮助提供类型例如:

1、声明变量\textcolor{Red}{并且}初始化值的时候

let test = 18; //ts会自动判断test的类型时number类型,鼠标放在上面会看到
let test; //知声明并没有初始化值的时候建议写法如下
let test: number;

2、决定函数返回值的时候

function test(num1: number, num2: number) {
  return num1 + num2;
}

4.10、类型断言

当你特别清楚要是用什么类型的时候采用类型断言

let test = HTMLElement; //(类型推论机制符合第一条,可以不写)
let test = document.getElementById('id'); 

getElementById方法返回值时HTMLElement该类型包含所有标签公共属性或方法,不包含a标签特有的href等属性

使用类型断言来指定更加具体的类型

let test = document.getElementById('id') as HTMLAnchorElement; //推荐
let test = <HTMLAnchorElement>document.getElementById('id'); //不常用知道即可

HTMLAnchorElement时A标签的类型,也是HTMLElement的子类型

查看元素类型通过浏览器控制台:console.dir()

4.11、字面量类型

使用场景:一般用于一组明确可选列表

let test = 'hello'; //类型为string
const test = 'hello'; //类型为'hello'(const定义常量值不能变,所以类型也为hello)
let test: 12 = 12; //

字面量类型配合联合类型一起使用

function map(direction: 'up' | 'down' | 'left' | 'right') {  //只能从上下左右四个方向选择一个,更加的精准
  console.log(direction);
}

4.12、枚举

类似字面量 + 联合类型的组合的功能

enum Test { //定义
  Up,
  Down,
  Left,
  Right,
}
function test(direction: Test) {
  console.log(direction);
}

1、关键字 enum

2、约束枚举名称和枚举元素都首字母大写

3、枚举多个值用逗号隔开

4、定义枚举后直接使用枚举作为类型注解

5、枚举元素如若未定义值默认从零开始一次加1,这样的称(数字枚举)也可以给元素赋值

enum Test {
  Up = 10,
  Down,
  Left,
  Right,
} //从10开始,依次是10,11,12,13
enum Test {
  Up = 2,
  Down = 4,
  Left = 6,
  Right = 8,
} //

6、字符串枚举(注:字符串枚举子增长行为,字符串枚举每个元素必须有值)

enum Test {
  Up = 'Up',
  Down = 'Down',
  Left = 'Left',
  Right = 'Right',
} //

枚举与字面量类型+联合类型相比,推荐字面量类型+联合类型,因为:编译为js时字面量类型+联合类型会被直接删除,而枚举则会编译为js代码,降低性能

4.13、any(不推荐了解即可)

let test: any = { test: 0 }; //你可以对test做任意操作但是ts不会给出任何提示
test.test1 = 100; //
test(); //
const test2: number = test; //

1、any类型声明变量不提供类型也不提供默认值,类似any类型

2、函数参数不加类型,也类似any类型

4.14、typeof获取数据类型

console.log(typeof 'hello'); //string

ts中typeof可以用来查询已有变量的类型,例如

let p = { x: number, y: number };
function test(test: { x: number; y: number }) {} //
function test(test: typeof p) {} //简化写法,效果一样,(推荐)
let num: typeof p.x; //拿到p中的x的元素类型

注:只用来查询变量或属性的类型,无法查询其他形式的类型(比如:函数调用的类型)

5、TypeScript高级类型

TS中的高级类型有很多,重点学习以下高级类型:

1、class类

2、类型兼容性

3、交叉兼容性

4、泛型和keyof

5、索引签名类型和索引查询类型

6、映射类型

5.1、class类

TS全面支持ES5引入的class关键字,还增添了类型注解和其他语法(比如可见性修饰符)

class Person {
  age: number;
  name: string;
  constructor(age: number, name: string) {
    this.age = age;
    this.name = name;
  }
} //class类
const p = new Person(18, '张三'); //初始化

函数是需要返回值类型的,否则会被推断为any类型;构造函数不需要返回值类型

实例方法

class Person {
  age: 18;
  play(age: number): void {
    console.log((this.age *= age));
  }
} //class类
const p = new Person();

class类继承,1、extends(继承父类)2、implements(实现接口)

说明:JS中只有extends,而implement是TS提供的

extends继承

class Person {
  move() {
    console.log('moving');
  }
}
class Dog extends Person {  //通过extends继承Person类的move方法
  run() {
    console.log('running');
  }
}
const D = new Dog();
D.move(); //moving

implements(实现接口)

interface Test {
  name: string;
  play(): void;
}
class Person implements Test {  //Person类通过implements实现接口时,必须提供接口中的所有属性和方法
  name: 'zhangsan';
  play() {
    console.log('play');
  }
}

类成员的可见性:可以使用TS来控制class的方法和属性是否可见。

可见性修饰包括:1、public(共有的)2、protected(受保护的)3、private(私有的)

1、public:表示公开,共有,都可以访问的,(默认public)

class Person {
  public plsy() {} //默认public可以不写
}

2、protected:表示受保护的,仅对其生命所在和子类中(非实例对象可见)

class Person {
  protected play() {}
}
class People extends Person {
  test() {
    this.play();
  }
}

3、private:表示私有的,只有在当前类之中可见

class Person {
  private study() {}
  read() {
    this.study();
  }
}

只读修饰符readonly:表示只能读取,不能修改

注:只可以修饰属性,不可以修饰方法,

class Person {
  readonly name = 'zhangsan'; //字面量类型,zhangsan
  readonly name: string = 'zhangsan'; //string类型
  constructor(name: string) {
    this.name = name;
  }
}

接口或{}表示对象类型,也可以用readonly

interface Test {
  readonly name: string;
}
let test: Test = {
  name: 'jack',
};
let test: { readonly name: string } = {
  name: 'jack',
};

5.2、类型兼容性

两种类型系统:

1、Structural Type System(结构化类型系统)2、Nominal Type System(标明类型系统)

TS采用的是结构化类型系统,也叫做duck typing(鸭子类型),类型检查关注的是值所具有的形状。

也就是说,如果两个对象的具有相同的形状,则认为他们是同一类型

原则:属性多的兼容属性少的(参数少的可以赋值给参数多的)

class Test1 {
  name: string;
  age: number;
}
class Test2 {
  name: string;
  age: number;
}
let test3: Test1 = new Test2(); //TS是结构化类型系统,只检查Test1和Test2的结构是否相同

在结构化类型系统中,如果说两个对象拒用相同的结构,则认为他们是同一类型,这种说法并不准确

更为准确的说法是:对于对象类型来说属性多的可以兼容属性少的(前提:属性多的要完完全全的包含属性少的所有属性)

class Test1 {
  name: string;
  age: number;
}
class Test2 {
  name: string;
  age: number;
  height: number;
} //Test2包括Test1的所有属性
let p: Test1 = new Test2(); //Test2的属性比Test1的属性多(属性多的兼容属性少的)解析如下
let p = {
  name: 'string',
  age: 2,
}

接口兼容性与对象兼容性类型(属性多的兼容属性少的)

interface Test1 {
  name: string;
  age: number;
}
interface Test2 {
  name: string;
  age: number;
  height: number;
}
let case1: Test1;
let case2: Test2;
case1 = case2; //Test2的属性比Test1的属性多(属性多的兼容属性少的)

class与interface之间也可以兼容,原则:属性多的兼容属性少的

interface Test1 {
  name: string;
  age: number;
}
class Test2 {
  name: string;
  age: number;
  height: number;
}
let p: Test1 = new Test2();

函数类型兼容性比较复杂,影响因素有多个,例如

1、参数的个数:参数多的兼容参数少的

type Test1 = (name: string, age: number) => void;
type Test2 = (name: string, age: number, height: number) => void;
let case1: Test1;
let case2: Test2;
case2 = case1;

2、参数的类型:相同位置的参数类型要相同(原始类型)或兼容(对象类型或接口类型)

相同

type Test1 = (name: string, age: number) => void;
type Test2 = (name: string, age: number) => void;
let case1: Test1;
let case2: Test2;
case2 = case1;
case1 = case2;

兼容

interface Test1 {
  name: string;
  age: number;
}
interface Test2 {
  name: string;
  age: number;
  height: number;
}
type Case1 = (test: Test1) => void;
type Case2 = (test: Test2) => void;
let case1: Case1;
let case2: Case2;
case2 = case1;

3、函数的返回值类型

1、如果是原始类型,相同即可

type Test1 = () => void;
type Test2 = () => void;
let case1: Test1;
let case2: Test2;
case2 = case1;
case1 = case2;

2、如果对象类型,兼容即可

type Test1 = ({ name: string, age: number }) => void;
type Test2 = ({ name: string, age: number, height: number }) => void;
let case1: Test1;
let case2: Test2;
case2 = case1;

5.3、交叉类型

交叉类型(&)类似接口继承(extends)用于组合多种类型(常用于对象类型)

interface Test1 {
  name: string;
  age: number;
}
interface Test2 {
  name: string;
  age: number;
}
type Test3 = Test1 & Test2; //Test3同时具备了Test1和Test2的所有属性

交叉类型与接口继承不同点

如果实现组合是有同名属性,继承会直接报错,交叉会将两种类型采用并集的方式处理,请看下面代码

interface Test1 {
  fn(value: number): void;
}
interface Test2 extends Test1 {  //会直接报错
  fn(value: string): void;
}
interface Test1 {
  fn(value: number): void;
}
interface Test2 {
  fn(value: string): void;
}
type Test3 = Test1 & Test2; //相当于下面代码
interface Test3 {
  fn(value: string): void; //做并集处理采用或的方式进行处理要么选择第一个要么选择第二个
  fn(value: number): void; //两个选其一
}
interface Test1 {
  fn(value: number): void;
}
interface Test2 {
  fn(age: number): string;
}
type Test3 = Test1 & Test2; //相当于下面代码
let p: Test3 = {
  fn(value: number) {}, //做并集处理采用或的方式进行处理要么选择第一个要么选择第二个
  fn(age: number) {    //两个选其一
    return '';
  },
};

5.4、泛型

泛型是在可以保证类型安全的前提下,让函数与多种类型一起工作,从而实现服用,常用于函数、接口、class中。

需求:传入一个数据,传入什么类型就以什么类型输出(参数与返回值类型相同)语法:<>

function Passvalue<Type>(value: Type): Type {  //类型变量
  return value;
}
let i = Passvalue<number>(10); //调用传变量名和值
let i = Passvalue<string>('10');
function Passvalue<Type>(value: Type): Type {  //类型变量
  return value;
}
let i = Passvalue(10); //TS会采用参数类型推断机制来判断Type的类型(简单写法)
let i = Passvalue('10');

泛型约束:默认情况下,泛型函数中的类型变量可以代表多种变量,这导致无法访问任何属性 ,这时就需要泛型约束(缩小类型的取值范围)

指定类型约束

function Passvalue<Type>(value: Type[] | ''): Type[] | '' {
  console.log(value.length);
  return value;
}
let i = Passvalue([]);
let i = Passvalue('');

extends添加约束

interface Test {
  length: number;
}
function Passvalue<Type extends Test>(value: Type): Type {
  console.log(value.length);
  return value;
}
let i = Passvalue([]);
let i = Passvalue('');

泛型有多个类型变量

function Passvalue<Type, Key extends keyof Type>(obj: Type, key: Key) {
  return obj[key];
}
Passvalue({ name: 'lisi', age: 18 }, 'name');
Passvalue(1, (可以访问对应的方法例如tostring等等));
Passvalue('abcd', (可以访问对应的方法例如tostring等等));//当输入数字时则是对应的索引,当输入高于字符串长的值时则输出undefind

keyof关键字接收一个对象类型,生成其键名称(可能时字符串或数字)的联合类型

key的值被限制在Type的所有键之一,或只能访问对象中存在的属性

泛型接口:接口也可以配合泛型来使用,增加其灵活性,增强复用性

interface Test<Type> {  //接口的类型变量,对接口的其他成员可见,所有成员都可以使用
  fn(value: Type): Type;
}
let Test1: Test<number> = {  //使用泛型接口时,需要显示指定的具体类型
  fn(value) {
    return value;
  },
};

泛型数组:JS中的数组在TS中就是一个泛型接口

const str: Array<string> = ['a', 'b', 'c']; //类似接口写法Arrey接口名称<string>类型变量

泛型类:class也可以配合泛型来使用

class Test<Type> {  //泛型类类似泛型接口,同样在类名称之后添加<>
  name: Type;
  add: (age: Type, height: Type) => Type;
}

泛型工具类型:都是基于泛型实现的,因为是内置,可以直接使用

1、Partial<Type>:用来创建一个类型,将Type的所有属性设置为可选

interface Person {
  name: string;
  age: number;
}
type Man = Partial<Person>; //解析为下面代码
interface Man {
  name?: string;
  age?: number;
}

2、Readonly<Type>:用来构造一个类型,将Type的所欲类型都设为Readonly(只读)

interface Person {
  name: string;
  age: number;
}
type Man = Readonly<Person>; //解析为下面代码
interface Man {
  readonly name: string;
  readonly age: number;
}

3、Pick<Type,Keys>从Type中选择一组数据来构造新类型

interface Person {
  name: string;
  age: number;
  height: number;
}
type Man = Pick<Person, 'name' | 'age'>; //解析为下面代码
interface Man {
  name: string;
  age: number;
}

4、Record<Keys,Type>构建一个对象类型,属性键为Keys,属性为Type(Keys为元素,Type为元素的类型)

type Man = Record<'name' | 'age', string>; //解析为下面代码
type Man = {
  name: string;
  age: string;
};

5.5、索引签名类型

索引签名类型:当无法确定对象中有那些属性时,采用索引签名类型。

interface Test {
  [key: string]: number; //接口内的元素名称的类型和元素值的类型
}
let Test1: Test = {
  a: 2,
};

注:所有的类型做都都将转换string类型,所以string类型可以代替所有类型

interface Test<Type> {
  [key: number]: Type; //接口内的元素名称的类型和元素值的类型
}
let Test1: Test<number> = [1, 3, 5];

数组情况

5.6、映射类型

映射类型:通俗来讲就是将一个存有多个key的集合,把每一个属性都复制到新对象中并设置属性

联合类型创建新类型:将联合类型内的所有元素复制到新类型中,并且为所有属性设置类型

type Keys = 'x' | 'y' | 'z'; //多个Key的集合
type Test = {
  [key in Keys]: number; //复制并设置属性
}; //解构如下
type Test = {
  x: number;
  y: number;
  z: number;
};

对象类型创建新类型:将对象类型内的所有元素复制到新类型中,并且所有属性的类型会被重新设置

type Keys = {
  name: string;
  age: number;
  height: number;
};
type Test = {
  [key in keyof Keys]: number; //复制并设置属性
}; //解构如下
type Test = {
  name: number;
  age: number;
  height: number;
};
let h: Test = {  //调用
  name: 1,
  age: 1,
  height: 1,
};

泛型工具类型都是基于映射类型实现的

例如Partial<Type>的实现:

type Partial<Type> = {
  [key in keyof Type]?: Type[key]; //拿到每个属性以及对应的类型
}; //上面代码理解即可
type Test = {
  x: number;
  y: number;
  z: number;
};
type Test1 = Partial<Test>; //Partial是内置直接使用即可
let h: Test1 = {
  //调用,Partial是将传输的类型中的属性全部变为可选择传输,所以即使没有z属性也不会报错
  x: 1,
  y: 2,
};

解释:使用Partial<传输一个对象类型或其他类型>,将里面所有的元素以及对应的属性一起复制到新类型之中

Type[key]这种语法叫做索引查询(访问)类型

作用:查询属性的类型

type Test = {
  x: number;
  y: string;
  z: boolean;
};
let test1: Test['x']; //拿到Test中x的类型并设置test1为同样的类型
type test3 = Test['x' | 'y']; //同时拿到多个类型,解析如下
type test3 = number | string;
type test3 = Test[keyof Test]; //拿到所有类型,解析如下
type test3 = number | string | boolean;

6、TypeScript类型声明文件

作用:为已存在的JS库提供类型信息

6.1、TS中的两种文件类型

1、.ts文件

既包含类型信息又包含可执行代码

可以被编译为.js文件,执行代码

代码编写的地方

2、.d.ts文件

只包含类型信息的类型声明文件

不会生成.js文件,仅用于提供类型信息

为js提供类型信息

6.2、类型声明文件的使用说明

学习顺序:先会用(别人的),再会写(自己的)

1、使用已有的类型声明文件

(1)内置类型声明文件:TS为JS运行时可用的所有标准化内置API都提供了声明文件

可以通过ctrl+单机来查看内置类型声明文件内容

(2)第三方库的类型声明文件

1.库自带类型声明文件

2.由DefinitelyTyped提供:是一个Git仓库用来提供高质量TypeScript类型声明

2、创建自己的类型声明文件

(1)项目内共享类型

1.创建index.d.ts类型声明文件

2.创建需要共享的类型,并使用export导出(TS中也可以使用import/export实现模块化功能)

3.在需要使用共享类型的.ts文件中,通过import导入即可(.d.ts文件导入时,直接省略后缀即可)

(2)为已有的js文件提供类型声明

关键字(declare):为已存在的变量提供类型

js文件

let test = 18;

ts文件

declare let test: number;

注:对于type、interface等明确就是ts类型的,可以省略declare,对于let、function等具有双重含义的应该使用declare

  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值