ts 带来了什么优势
- 可以对变量进行类型约束
- 能在代码编辑器中有更好的代码提示
- 能在开发过程中避免一些潜在的风险
ts 类型
type annotation;//类型注解,手动告诉ts变量的类型
type inference; //类型推断,自动分析变量类型
const number = 1; //可以自动推断出来类型
//任何为any的值均需要添加类型注解
//函数形参需要指定类型,返回值不一定需要指定
function getTotal(n1:number,n2:number):number{
return n1 + n2;
}
const res = getTotal(1,2); //此处不需要指定
基础类型
- number
- string
- boolen
- null
- undefined
- void
- symbol
- never : 函数不会执行完会返回 never
对象类型
- array
- object
- Function
数组
const nums = [1, 2, 3]; //可以自动推断 number []
const arr: (number | string)[] = [1, '2', 3]; //混合类型数组
const objArr: { name: string; age: number } = [{ name: 'jack', age: 18 }];
// 通过这种语句定义查看会比较难,可以通过type或者interface来定义类型
type User = { name: string; age: number };
interface User {
name: string;
age: number;
}
const objArr: User[] = [{ name: 'jack', age: 18 }];
元组 Tuple
//数组长度,类型固定时会使用元组,通常在读取excel,csv文件时会用到
//数量格式有限的数组
const info: [string, string, number] = ['jack', 'male', 18];
const infos: [string, string, number][] = [
['jack', 'male', 18],
['alice', 'female', 20],
];
interface 接口
当同一个类型需要多次使用时,多个相同的类型注解可能会导致代码逻辑冗余,可以抽离出来
interface 和 type 不同点: type可以接受一个基础类型,而interface只能为一个对象
interface Person {
readonly name: string; //只读
age?: number; // ?为可空操作符
}
class 类
访问类型有三种 private,protected,public
默认为public
- public是公共成员,允许在类外被调用,是外部可访问的
- private是私有成员,无法被外部访问
- protected为受保护成员,允许在内部和继承的子类中使用,外部不可调用
class Person {
private name: string;
constructor(name: string, public weight: number, public height: number) {
this.name = name;
}
}
构造函数里对参数使用访问修饰符是语法糖,可以不使用this,可以被继承
子类继承必须要在ctor中添加super调用
静态属性
- getter / setter
- readonly
class Person(){
constructor(pirvate _name:string){}
get getName(){
return this._name;
}
set setName(v:string){
this._name = v;
}
}
抽象类
- 抽象出来的一些共有属性
- 只能被继承,不能被实例化
与接口的区别
- 接口和抽象类都不能被实例化
- 接口是把共有函数,共有属性抽离出来
- 接口只能包含方法的定义,不能提供方法的实现
- 抽象类可以包含普通方法以及方法的实现
联合类型和类型保护
interface Bird {
fly: boolean;
sing: () => {};
}
interface Dog {
fly: boolean;
bark: () => {};
}
type Animal = Dog | Bird;
//联合类型只会取共有的属性
function train(animal: Animal) {
//想避免错误可以使用类型断言as
if (animal.fly) {
//因为Bird的fly一定是true,所以说可以断言animal为Bird
(animal as Bird).sing();
} else {
(animal as Dog).bark();
}
//也可使用in关键字语法做类型保护
if ('sing' in animal) {
animal.sing();
} else {
animal.bark();
}
}
泛型
function fun<T>(arg: T): T {
return arg;
}
泛型在很多编程语言中都有,指泛用的类型,可以用来取代联合类型,使代码更简洁。
当然这里也可以使用 any 来替代泛型,但是使用 any 类型会导致函数可以接收任何类型的 arg 参数,但是这样就会丢失类型保护机制,以及编辑器中的智能提示,会导致 TS 无法跟踪函数里使用的类型的信息。
let output = fun<string>('string');
这样就指定了 T 是 string 类型,并做为一个参数传给函数 注意类型要使用<>括起来而不是()
简单使用时,其实没必要使用尖括号<>来明确地传入类型;TS 有类型推断,编译器会根据传入的参数自动地帮助我们确定 T 的类型,只有在复杂情况下导致无法推断出来
let output = fun('string');
我们有时候想操作某类型的一组值,并且我们知道这组值具有什么样的属性,所以会去写我们能知道的一些属性,但是 TS 编辑器不会识别类型中的属性,所以就会报错
function len<T>(arg: T) {
return arg.length; // Error: 类型“T”上不存在属性“length”
}
为了解决这个问题,我们可以给泛型加上类型约束
interface Length {
length: number;
}
function len<T extends Length>(arg: T) {
return arg.length;
}
通过这种方式给类型添加上约束,就不会报错,但是也导致了另一个问题就是 T 无法代表任意的类型。
len(1); //Error: 类型“number”的参数不能赋给类型“Length”的参数。
这时候需要传入符合约束类型的值,必须包含必须的属性,以下代码就不会有错误
len([1, 2, 3]);
len({ length: 1, value: 'abc' });