符号
& 交叉类型
交叉类型是一种将多种类型组合为一种类型的方法。 这意味着你可以将给定的类型 A 与类型 B 或更多类型合并,并获得具有所有属性的单个类型
type LeftType = {
id: number;
left: string;
};
type RightType = {
id: number;
right: string;
};
type IntersectionType = LeftType & RightType;
function showType(args: IntersectionType) {
console.log(args);
}
showType({ id: 1, left: 'test', right: 'test' });
// Output: {id: 1, left: "test", right: "test"}
语法提示会提示联合后的所有的属性
同时,类型校验的时候也会校验交叉后的所有属性
| 联合类型
联合类型使你可得到多个类型中公共属性组成的类型,最后得到的类型只包含所有联合项的公用属性
type UnionType = string | number[];
function showType(arg: UnionType) {
console.log(arg.length)
arg.forEach()
// 类型“UnionType”上不存在属性“forEach”。
//
类型“string”上不存在属性“forEach”。ts(2339)
}
showType([1])
showType('1')
联合类型只能拿到组合前的共有属性
! 非空断言操作符
在上下文中当类型检查器无法断定类型时,一个新的后缀表达式操作符 ! 可以用于断言操作对象是非 null 和非 undefined 类型。具体而言,x! 将从 x 值域中排除 null 和 undefined 。
那么非空断言操作符到底有什么用呢?下面我们先来看一下非空断言操作符的一些使用场景。
忽略 undefined 和 null 类型
function myFunc(maybeString: string | undefined | null) {
// Type 'string | null | undefined' is not assignable to type 'string'.
// Type 'undefined' is not assignable to type 'string'.
const onlyString: string = maybeString; // Error
const ignoreUndefinedAndNull: string = maybeString!; // Ok
}
调用函数时忽略 undefined 类型
type NumGenerator = () => number;
function myFunc(numGenerator: NumGenerator | undefined) {
// Object is possibly 'undefined'.(2532)
// Cannot invoke an object which is possibly 'undefined'.(2722)
const num1 = numGenerator(); // Error
const num2 = numGenerator!(); //OK
}
注意⚠️: 谨慎使用非空断言,尤其是函数类型的。这很可能事变量被错误的使用
?. 可选链条
可选链条并不是类型操作语法,而是ESnext规范的一部分
有了可选链后,我们编写代码时如果遇到 null 或 undefined 就可以立即停止某些表达式的运行。可选链的核心是新的 ?. 运算符,它支持以下语法:
obj?.prop
obj?.[expr]
arr?.[index]
func?.(args)
上述的代码会自动检查对象 a 是否为 null 或 undefined,如果是的话就立即返回 undefined,这样就可以立即停止某些表达式的运行。你可能已经想到可以使用 ?. 来替代很多使用 && 执行空检查的代码
注意⚠️ :
1. ?. 与 && 运算符行为略有不同, && 专门用于检测 falsy 值,比如空字符串、0、NaN、null 和 false 等。而 ?. 只会验证对象是否为 null 或 undefined ,对于 0 或空字符串来说,并不会出现 “短路”。
2.可选链条与函数调用
let result = obj.customMethod?.();
由于可以选链条只判断 undefined或null,所以customMethod为非函数数据时,也会被调用且报错
??空值合并运算
类似 || ,但只检验左侧是否为undefined或null
const foo = null ?? 'default string';
console.log(foo); // 输出:"default string"
const baz = 0 ?? 42;
console.log(baz); // 输出:0
短路属性
当空值合并运算符的左表达式不为 null 或 undefined 时,不会对右表达式进行求值
function A() { console.log('A was called'); return undefined;}
function B() { console.log('B was called'); return false;}
function C() { console.log('C was called'); return "foo";}
console.log(A() ?? C());
console.log(B() ?? C());
/*
* A was called
* C was called
* foo
* B was called
* false
/
不能与 || && 共用
\
关键字
extends
类型继承
interface Person {
name: string;
age: number;
}
interface Player extends Person {
item: 'ball' | 'swing';
}
// Player会有Person的属性
做断言
// 如果 T 可以满足类型 Person 则返回 Person 类型,否则为 T 类型
type IsPerson<T> = T extends Person ? Person : T;
typeof
在 TS 中用于类型表达时,typeof 可以用于从一个变量上获取它的类型
let a = '1';
let obj = {
'a': 1,
'b': 2
}
let obj2 = {
'a': 1,
'b': 2
} as const;
type IA = typeof a;
type IObj = typeof obj
type IObj2 = typeof obj2;
// type IA = string
// type IObj = {
a: number;
b: number;
}
// type IObj2 = {
readonly a: 1;
readonly b: 2;
}
keyof
keyof 是TS中的索引类型查询操作符。keyof T 会得到由 T 上已知的公共属性名组成的联合类型。
interface Person {
name: string;
age: number;
phoneNum: number;
}
type PersonProperty = keyof Person;
// type PersonProperty = "name" | "age" | "phoneNum"
简单的应用场景
// 配合范型使用
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
来点高阶的 获取类型中属性的key 和 值(的类型)
type IValueByKey = {
[key: string| number| symbol]: any
}
type GetKeys<T extends IValueByKey>= keyof T
type GetValue<T extends IValueByKey>= T[keyof T]
const obj = {
name: 'liu',
age: '27'
}
const obj1 = {
name: 'liu',
age: '27'
} as const
type ObjKey = GetKeys<typeof obj> // "name" | "age"
type ObjValue = GetValue<typeof obj> // string
type ObjKey1 = GetKeys<typeof obj1> // "name" | "age"
type ObjValue1 = GetValue<typeof obj1> // "liu" | "27"
in
用来遍历可枚举类型通常是枚举类型或联合类型,遍历出的key可以做类型的属性名
enum Letter {
A,
B,
C,
}
type LetterMap = {
[key in Letter]: string;
}
// type LetterMap = {
// 0: string;
// 1: string;
// 2: string;
// }
type Property = 'name' | 'age' | 'phoneNum';
type PropertyObject = {
[key in Property]: string;
}
// type PropertyObject = {
// name: string;
// age: string;
// phoneNum: string;
// }
type IB = {
[key in PropertyKey]: PropertyKey
}
let key = Symbol();
let b:IB = {
name: '1',
1: '2',
key:'ss'
}
通常配合keyof使用,因为keyof返回的是联合类型
infer
我理解的infer是配合extends做类型推断
比如 我们预期范型T是个数组类型,我们想知道T具体是什么类型的书组
比如 我们预期范型T是函数,我们想得到T参数和返回值的类型
// 获取函数的参数类型
type ParamType<T> = T extends (...args: infer R) => any ? R : any;
type func = (a: string, number: number) => number;
type funcParamType = ParamType<func>;
// type funcParamType = [a: string, number: number]
// 获取函数返回值类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type func = () => number;
type funcReturnType = ReturnType<func>; // funcReturnType 类型为 number
// 对象的联合类型推断
type Foo<T> = T extends { a: infer U; b: infer U } ? U : never;
type T10 = Foo<{ a: string; b: string }>; // T10类型为 string
type T11 = Foo<{ a: string; b: number }>; // T11类型为 string | number
// 数组的基本类型推断
type Nums = [string];
type BasicType<T> = T extends (infer R)[] ? R : any
type Basic = BasicType<Nums> // numbr
工具范性
Partial 全部属性可选
type Partial<T> = {
[P in keyof T]?: T[P];
};
interface PartialType {
id: number;
firstName: string;
lastName: string;
}
/*
等效于
interface PartialType {
id?: number
firstName?: string
lastName?: string
}
*/
function showType(args: Partial<PartialType>) {
console.log(args);
}
showType({ id: 1 });
// Output: {id: 1}
showType({ firstName: 'John', lastName: 'Doe' });
// Output: {firstName: "John", lastName: "Doe"}
Required 全部属性必选
type Required<T> = {
[P in keyof T]-?: T[P];
};
interface RequiredType {
id: number;
firstName?: string;
lastName?: string;
}
function showType(args: Required<RequiredType>) {
console.log(args);
}
showType({ id: 1, firstName: 'John', lastName: 'Doe' });
// Output: { id: 1, firstName: "John", lastName: "Doe" }
showType({ id: 1 });
// Error: Type '{ id: number: }' is missing the following properties from type 'Required<RequiredType>': firstName, lastName
Readonly
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
interface ReadonlyType {
id: number;
name: string;
}
function showType(args: Readonly<ReadonlyType>) {
args.id = 4;
console.log(args);
}
showType({ id: 1, name: 'Doe' });
// Error: Cannot assign to 'id' because it is a read-only property.
// 也可单独指定某个属性
interface ReadonlyType {
readonly id: number;
name: string;
}
as const 会把对象Readonly化
// const obj = {
// a: '1',
// b: '2'
// } as const
// 等价于
type IReadOnlyObj = {
readonly a: '1',
readonly b: '2'
}
const obj:IReadOnlyObj = {
a: '1',
b: '2'
}
Pick 属性选择
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
此方法允许你从一个已存在的类型 T中选择一些属性作为K, 从而创建一个新类型
即 抽取一个类型/接口中的一些子集作为一个新的类型
T代表要抽取的对象
K有一个约束: 一定是来自T所有属性字面量的联合类型
新的类型/属性一定要从K中选取
interface PickType {
id: number;
firstName: string;
lastName: string;
}
function showType(args: Pick<PickType, 'firstName' | 'lastName'>) {
console.log(args);
}
showType({ firstName: 'John', lastName: 'Doe' });
// Output: {firstName: "John"}
showType({ id: 3 });
// Error: Object literal may only specify known properties, and 'id' does not exist in type 'Pick<PickType, "firstName" | "lastName">'
Omit 属性删除
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
interface PickType {
id: number;
firstName: string;
lastName: string;
}
function showType(args: Omit<PickType, 'firstName' | 'lastName'>) {
console.log(args);
}
showType({ id: 7 });
// Output: {id: 7}
showType({ firstName: 'John' });
// Error: Object literal may only specify known properties, and 'firstName' does not exist in type 'Pick<PickType, "id">'
Extract<T, U> 提取交集属性
type Extract<T, U> = T extends U ? T : never;
Extract允许你通过选择两种不同类型中的共有属性来构造新的类型。 也就是从T中提取所有可分配给U的属性。
interface FirstType {
id: number;
firstName: string;
lastName: string;
}
interface SecondType {
id: number;
address: string;
city: string;
}
type ExtractType = Extract<keyof FirstType, keyof SecondType>;
// Output: "id"
在上面的代码中,FirstType接口和SecondType接口,都存在 id:number属性。 因此,通过使用Extract,即提取出了新的类型 {id:number}。
Exclude<T, U> 剔除交集属性
type Exclude<T, U> = T extends U ? never : T;
interface FirstType {
id: number;
firstName: string;
lastName: string;
}
interface SecondType {
id: number;
address: string;
city: string;
}
type ExcludeType = Exclude<keyof FirstType, keyof SecondType>;
// Output; "firstName" | "lastName"
注意⚠️: 剔除和提取都是以T为基准的,最后的类型中不会含有T中没有的属性
Record<T,U> 属性映射
type Record<K extends keyof any, T> = {
[P in K]: T;
};
此工具可帮助你构造具有给定类型T的一组属性K的类型。将一个类型的属性映射到另一个类型的属性时,Record非常方便
比如一个经典场景,后端数据某一个层的key是可枚举的,下一层级的数据接口又很复杂
type Pro = {
a: string;
b: string;
c?: number;
d: {
e: string
}
}
const hashlist = ['hash1', 'hash2' , 'hash3'] as const
type Getprokey<T> = T extends readonly (infer R)[] ? R : any;
type PorKey = Getprokey<typeof hashlist> // 'hash1'|'hash2'|'hash3'
function ctrResult(res: Record<PorKey, Pro>){
//
}
export {}