Typescript
类型
String string 区别
const msg: string = 'hello'; // 一般都写小写就ok了
const message: String = 'hello';
// 这个就代表这个文件是独立的模块, 就不会报在其他文件里重名的错误了
export {};
这边冒号后面的类型是区分开来的
- strinig: 代表 ts 中的字符串类型
- String: 代表 js 中字符串包装类的类型
类型推导
let foo = 'cqc'; // 在默认情况下赋值, ts会自动将赋值的类型作为签名标识符的类型
foo = 123456; // 这里会报错 Type 'number' is not assignable to type 'string'.
数据类型 ( js 中存在的 )
默认情况下如果可以推导出(infer)标识符的类型时候 一般不手动加类型
数值 number
//? number
// ts 数值类型不区分 int float
let num1: number = 213; // 普通数值
let num2: number = 0b111; // 二进制
let num3: number = 0o456; // 八进制
let num4: number = 0x9ac; // 十六进制
布尔 boolean
// ? boolean
let flag1 = 2 > 3;
let flag2 = false;
字符 string
数组 Array
// 一个数据中存放的元素类型应该是固定的
// 注意这里是Array 不是 array
const arr1: Array<string> = ['cqc']; // 不推荐(jsx 中冲突)
const arr2: string[] = ['cqc']; // 推荐 效果同arr1
对象 object
// 可以赋默认值 自动推导
const info1 = {
name: 'cqc',
age: 24,
};
// 十分不推荐(使用info2.name的时候不会自动弹出提示 且报错 Property 'name' does not exist on type )
const info2: object = {
name: 'cqc',
};
空值 null
// null 类型只有一个 null 的值 只能赋值 null
const nl: null = null; // null 类型时候最好手动指定下类型(否则类型自动推导是 any)
未定义 undefined
// 和 null 类型一样 只有一个值 只能赋值 undefined
const und: undefined = undefined;
唯一 symbol
数据类型 ( ts 中独有的 )
any
-
应用场景 当进行一些类型断言的时候 as any 否则报错 在不想给某些 js 添加具体数据类型时候 any-script?
const arr: any[] = [];
unknown
类似 any 类型, 用于不确定类型 在不能推导出来的时候使用 (可能是类型 a 可能是类型 b)
unknown、any 区别
unknown 类型的数据只能赋值给 unknown 类型 或者 any 类型, 但是 any 类型可以赋值任意类型
let unknown1: unknown;
let any1: any;
const str1: string = any1;
// ok
const str2: string = unknown1;
// Type 'unknown' is not assignable to type 'string'
void
// 指定一个函数返回值类型 只能是 null || undefined
const foo = function (str: string): void {
return null || undefined;
};
never
表示一个函数永远不会发生值的类型
应用场景
const foo = function (): never {
// while( true ) {};
throw new Error();
};
const handler = function (message: string | number) {
switch (typeof message) {
case 'string':
...
break;
case 'number':
...
break;
default:
// 函数进入这里就会报错
const check: never = message;
break;
}
};
// 这时候加入有人需要用 handler 函数处理其他类型, 那么他有可能在联合类型内加入他要处理的类型 比如:
const handler = function (message: string | number | boolean) {...};
// 这时候 handler 函数内没有处理到 boolean 这个新类型, switch 进入到 default 处理方式, 直接编译报错, 提醒人添加新类型的处理方式
元组 tuple
多种元素组合而成的数组
const tupleInfo: [string, number, number] = ['cqc', 1.7, 170];
// 应用场景
// 希望调用一个函数 得到 [counter, setCounter]
type MyFunction = <T>(state: T) => [T, (newValue: T) => void];
const useState: MyFunction = function useState<T>(state: T) {
let currentState = state;
const changeState = (newState: T) => {
currentState = newState;
};
return [currentState, changeState];
};
const [counter, setCounter] = useState(10);
枚举
// 默认值 从 0 开始
enum Direction {
LEFT, // 0
RIGHT, // 1
TOP, // 2
BOTTOM,
}
function turnDirection(direction: Direction) {
switch (direction) {
case Direction.LEFT:
// ...
break;
case Direction.RIGHT:
// ...
break;
// ...
default:
break;
}
}
turnDirection(Direction.RIGHT);
// 可以自定义值
enum DirectionMy {
TOP = 10,
BOTTOM = 20,
LEFT, // 21 会取上面那个 + 1
}
let d: DirectionMy = DirectionMy.TOP;
enum DirectionMy1 {
TOP = 'TOP', // 只可以是字符串
}
泛型(重要)
const foo = function <T, S>(typeT: T, typeS: S) {
const tupleArr: [T, S] = [typeT, typeS];
return tupleArr;
};
// 接口中使用泛型
interface IPerson<T1, T2 = number> {
// T2 使用了默认类型
name: T1;
age: T2;
}
const p: IPerson<string, number> = {
name: 'cqc',
age: 23,
};
// 类中使用泛型
class Point<T> {
x: T;
y: T;
constructor(x: T, y: T) {
this.x = x;
this.y = y;
}
}
const p = new Point('1.33', '2.22');
const p1 = new Point<string>('1.33', '2.22');
const p2: Point<string> = new Point('1.33', '2.22');
// 普通数组中使用泛型
const names: Array<string> = ['cqc']; // 不推荐
泛型的限制
interface ILength {
length: number;
}
interface IMy {
name: string;
}
const getLength: <T extends ILength & IMy>(arg: T) => number = function (arg) {
return arg.length;
};
getLength({ length: 3, name: 'cqc' });
函数参数和返回值类型
function sum1(n1: number, n2: number): number {
return n1 + n2;
}
const names = ['cqc', 'why', 'plo'];
//匿名函数 item根据上下文的环境推导出来,可以不写注解
names.forEach((item) => {
item.length; // item: string
});
// 定义常量时候
type AddFnType = (...args: number[]) => number;
const sum: AddFnType = (...args: number[]) => {
return args.reduce((p, c) => p + c);
};
sum(1, 2, 3, 1);
对象类型
type PrintType = {
x: number;
y: number;
z?: number; // 可选类型 效果和 z: number | undefined 一样
};
function printPoint(point: PrintType) {
console.log(point.x);
console.log(point.y);
console.log(point.z);
}
联合类型
使用联合类型值时候, 需要小心该值的类型 缺点:
- 进行很多逻辑判断(类型缩小)
- 返回值类型不能确定
function printID(id: number | string) {
id;
}
// 让传入的参数是可选的
function foo(name?: string) {}
类型别名
type IDType = string | number | boolean;
类型断言 as
类型断言只允许转换为 更具体 或 不太具体的 类型, 防止不可能的强制转换
// ? 类型断言 as
/*
默认这种方式获取的el 类型是 HTMLElement
但是不同html标签属性不一样
这时候可以使用类型断言
*/
const el = document.getElementById('img') as HTMLImageElement;
el.src; // 在不使用类型断言时候 Property 'src' does not exist on type 'HTMLElement'
// ---------
class Person {}
class Student extends Person {
study() {}
}
function satHi(p: Person) {
// 这里知道p是 Student, 直接断言
(p as Student).study();
}
const stu = new Student();
satHi(stu);
// ----------
// 不是特殊情况不推荐
const message = 'hello';
const num: number = message as number; // 报错
const num: number = message as unknown as number; // 需要先断言 known 在断言 number, 才能赋值
非空类型断言
function printMessage(message?: string) {
message!.toUpperCase(); // 这里加 ! 告诉ts编译器跳过对这部分的检查 但是调用该方法不传递参数 该报错还报错 printMessage()
}
字面量类型
字面量类型与他的值保持一致
const message: 'cqc' = 'cqc';
// 字面量类型的意义, 就是结合 联合类型 (和枚举类似)
type Align = 'left' | 'center' | 'right';
let align: Align = 'center';
// ------------
// 字面量推理
type Method = 'POST' | 'GET';
function request(url, method: Method) {}
// 一般建议直接给 options 定死类型
const option = {
url: 'https:/.xxx/a',
method: 'POST' as const, // 不加这个的话, 在调用 request 方法时候 这个属性类型会被定义 string, 加了后类型就是 POST
};
request(options.url, options.method);
操作符
- ?? 空值合并操作符
const a = false;
const b = 'cqc';
const res = a ?? b;
// 当 a 为 null || undefined 时候, 返回右边值, 否则返回左侧值
类型缩小
- 常见类型缩小方式
- typeof
- 平等缩小 ( === , !== )
- instanceof // 实例(==new 出来的==) instanceof 原型
- in
- ...
let a = xxx;
// 缩小类型范围
if(typeof a === 'string') {
...
}
switch(..) {
...
}
function printTime(time: string | Date) {
if (time instanceof Date) {
time.getTime()
}
}
// instanceof -------------
class Student {
studing() {}
}
class Teacher {
teaching() {}
}
function work(p: Student | Teacher) {
if (p instanceof Student) {
...
} else {
...
}
}
函数重载
函数名称相同,但是参数不同的几个函数 如果可以通过联合类型实现的函数重载, 直接联合类型 感觉函数重载比较鸡肋,最终函数逻辑的实现还是在一个函数体内去判断它的参数类型,然后做相应的操作。==ts 重载的作用,只是多了一个参数校验的功能==。
// 编写一个add函数, 可以数字之间相加、也可以数字、字符串
type AddType = number | string;
function add(a1: number, a2: number): number; // 没有函数体
function add(a1: string, a2: string): number;
function add(n1: any, n2: any): any {
if (typeof n1 === 'string' && typeof n2 === 'string') {
return n1.length + n2.length;
}
return n1 + n2;
}
const res = add('20', '5');
// 在函数重载中, 实现函数是不能直接被调用的
// add([], 123); //No overload matches this call.