ts 基础总结(从入门到放弃)
ts的好处自然不必多说,用就完了
以下是收集整理的一些比较基础的笔记总结
简单类型标注
基础类型包含:string,number,boolean
let str: string = "hh";
let str1: String = "gg";
// tips:
// str = str1; // 报错
// 不能将类型“String”分配给类型“string”。 “string”是基元,但“String”是包装器对象
// 如可能首选使用“string”。
// str = new String("哈哈"); // 报错
// str1 = str; // 可以
let num: number = 100;
let num1: Number = 200;
// number 和 Number同理
let isOk: boolean = true;
空和未定义类型
因为在 Null 和 Undefined 这两种类型有且只有一个值,在标注一个变量为 Null 和 Undefined 类型,那就表示该变量不能修改了
let a: null;
a = null; // ok
a = undefined; // ok
// a = 1; // error
let b: undefined;
b = null; // ok
b = undefined; // ok
// b = 1; // error
默认情况下 null 和 undefined 是所有类型的子类型。 就是说可以把 null 和 undefined 赋给其它类型的变量
let a: number;
// ok
a = null;
如果一个变量声明了,但是未赋值,那么该变量的值为 undefined ,但是如果它同时也没有标注类型的话,默认类型为 any
// 类型为 number,值为 undefined
let a: number;
let b;
// 类型为 any,值为 undefined
因为 null 和 undefined 都是其它类型的子类型,所以默认情况下会有一些隐藏的问题,比如:
let a: number;
a = null; // 此时可以赋值null给a
// error
a.toString(); // 而null 自然没有这个toString方法,此时将无法发挥ts的作用
可以通过 tsconfig.json 中 配置 strictNullChecks 为 true,可以有效的检测 null 或者 undefined 来规避此类问题
对象类型
内置对象类型
先说一下常用的内置对象类型:
ECMAScript 标准提供的内置对象:Boolean、Number、Math、Date、RegExp 等
标准内置对象
DOM 和 BOM 提供的内置对象:Document、HTMLElement、Event、NodeList 等
TypeScript 定义文件
很多时候我们需要使用到这些对象类型,比方说:
let d1: Date = new Date();
let body: HTMLElement = document.body;
自定义对象类型
更多时候我们需要定义具体的对象结构,这是可以有大致三种做法
- 字面量标注
// 优点 : 方便、直接,直接怼脸上
// 缺点 : 不利于复用和维护
let p: { username: string; age: number } = {
username: "小红",
age: 18,
};
- 接口 | 类型别名
interface:
// 优点 : 复用性高
// 缺点 : 接口只能作为类型标注使用,不能作为具体值,它只是一种抽象的结构定义,并不是实体,没有具体功能实现
interface Person {
username: string;
age: number;
}
let p: Person = {
username: "小红",
age: 18,
};
type:
type Person {
username: string;
age: number;
}
let p: Person = {
username: "小红",
age: 18,
};
interface 与 type 的区别
interface 只能描述 object 、 class 、 function 的类型,同名 interface 会自动合并,利于扩展
type 能描述包括联合类型、元祖类型、基础类型等所有数据,但是不能重名
二者标记函数时语法也有较大差别
type setNum = (x: number, y: number) => void;
interface setNum {
(x: number, y: number): void
}
同时二者也可以相互继承等等。。。这里就不多讲了,总得来说,推荐用interface,实在不行再用type
- 定义 类 或者 构造函数
// 优点 : 功能相对强大,定义实体的同时也定义了对应的类型
// 缺点 : 复杂,比如只想约束某个函数接收的参数结构,没有必要去定一个类,使用接口会更加简单
class Person {
constructor(public username: string, public age: number) {}
}
总得来说,如果没什么严格要求,可能某个地方就浅用一下,那字面量就可以了,如果希望
数组类型
- 泛型标注
let arr1: Array<number> = [];
- 简单标注
let arr2: string[] = [];
元组类型
let a: [string, number] = ['字符串', 123];
a.push(true); // error
let a: [string, number] = ['字符串', 123,false]; // error
枚举
枚举用于组织收集一组关联数据的方式或定义一些不具有语义性的常量,例如订单状态、http请求的code
enum HTTP_CODE {
OK = 200,
NOT_FOUND = 404
};
// 200
HTTP_CODE.OK;
此时需要使用200是可用HTTP_CODE.OK
要注意的是:
- key 不能是数字
- value 可以是数字,称为 数字类型枚举,也可以是字符串,称为 字符串类型枚举,但不能是其它
值,默认为数字:0 - 枚举值可以省略,如果省略,则:第一个枚举值默认为:0,非第一个枚举值为上一个数字枚举值 + 1
- 枚举值为只读(常量),初始化后不可修改
- 如果是字符串类型枚举,则后续枚举必须手动赋值
void、any、unknown
void
表示没有任何数据的类型,通常用于标注无返回值函数的返回值类型,函数默认标注类型为: void
function fn(): void {}
any
通常不会这样,除非真的不知道该值的类型或者真的不需要进行类型检测,因为标注为any后也就意味着放弃了IDE的智能提示,并且使用ts的类型检测也将毫无意义,到最后真成了anyscript
let a: any;
- 一个变量申明未赋值且未标注类型的情况下,默认为 any 类型
- 任何类型值都可以赋值给 any 类型
- any 类型也可以赋值给任意类型
- any 类型有任意属性和方法
unknow
3.0 版本中新增,属于安全版的 any,能用unknow就不用any但是与 any 不同的是:
- unknow 仅能赋值给 unknow、any
- unknow 没有任何属性和方法
let a: unknown;
a.b;// error
函数类型
一个函数的标注包含 参数、返回值,一般而言,函数的标注有如下形式
function fn(a: string): string {};
let fn: (a: string) => string = function(a) {};
type callback = (a: string): string;
interface ICallBack {
(a: string): string;
}
let fn: callback = function(a) {};
let fn: ICallBack = function(a) {};
可选参数
与对象中类似,通过参数名后面添加 ? 来标注该参数是可选的
function sum(a: number, b?: number) {
// ...
}
默认参数
function sum(a = 2, b : number = 1) {
// ...
}
- 有默认值,意味着可选
- 有默认值的参数,会自动进行类型推导
this
对于普通函数而言, this 是会随着调用环境的变化而变化的,所以默认情况下,普通函数中的 this
被标注为 any ,但我们可以在函数的第一个参数位(它不占据实际参数位置)上显式的标注 this 的
类型
interface T {
fn: (x: number) => void;
}
let obj2:T = {
fn(this: T, x: number) {
//通过第一个参数位标注 this 的类型,它对实际参数不会有影响
console.log(this);
}
}
箭头函数的 this 不能像普通函数那样进行标注,它的 this 标注类型取决于它所在的作用域 this
的标注类型
interface T {
a: number;
fn: (x: number) => void;
}
let obj2:T = {
a: 1,
fn(this: Window, x: number) {
return () => {
//this
this
}
}
}
类型推导
如果ts的类型标注每次都要显示标注,那显然有些不够友好,好在,ts拥有便捷的类型推导特性。
ts编译器会在初始化变量,设置函数默认参数,返回函数值时根据当前上下文自动推导出一些显然的类型,这大大减少开发者的苦恼。
// 此时没有显示标注类型,但ts自动推导出a为number类型
let a = 1;
// 不能将string分配给number
x = 'a';
// 相同的,函数参数类型、函数返回值也会根据对应的默认值和返回值进行自动推断
function fn(a = 1,b = 2) {return a + b}
类型断言
有时候开发者需要标注一个更加精确的类型时就可以使用到类型断言 as 或者 <>
// 此时img为Element
let img = document.querySelector('#img');
// 我们可以通过如下两种方式断言为更具体的:HTMLImageElement类型
let img = <HTMLImageElement>document.querySelector('#img');
// or
let img = document.querySelector('#img') as HTMLImageElement;
一般如下情况使用:
- 将一个联合类型断言为单一类型
- 将一个父类断言为具体的子类
- 将任何一个类型断言为any
- 将any类型断言为任意具体类型
类型断言只是一种预判,不会对数据本身的类型产生改变