vaakian / vaakian.github.io

some notes
https://vaakian.github.io
3 stars 0 forks source link

TypeScript——cheatSheet #41

Open vaakian opened 2 years ago

vaakian commented 2 years ago

some code snippet, for when i forgot.

类型推断 & 自动取类型

function generatePoint(x: number, y: number) {
    return { x, y }
}
// 取函数类型
type PointFunc = typeof generatePoint
// 单取函数返回值类型
type Point = ReturnType<PointFunc>
// 一句话
type Point = ReturnType<typeof generatePoint>

属性扩展

type Info = {
    age: number,
    name: string
}
// 1. & 交叉类型
type PersonInfo1 = Info & { userId: string }

// 2. extends 继承类型
interface PersonInfo2 extends Info {
    userId: string
}

⚠️注意:通过&运算符创建的属性如果重复/冲突时,后面的类型不会覆盖前面,而会变为never类型。而extends继承方式创建扩展类型时,会直接报错。

type Info = {
    age: number;
    name: string;
}
// 1. & 交叉类型
type PersonInfo1 = Info & { userId: string; age: string }
// 结果是
{
    name: string;
    userId: string;
    age: number & string; // number & string不可能出现,即为never类型
}

// 2. extends继承类型
interface PersonInfo2 extends Info {
    userId: string;
    age: string; // 直接报错
}

解决办法是有的,通过Omit操作符先去掉重复的属性,再重新定义。

type PersonInfo1 = Omit<Info, 'age'> & { userId: string; age: string }

interface PersonInfo2 extends Omit<Info, 'age'> {
    userId: string;
    age: string
}

更复杂的方式,age & name不可修改

type PersonInfo3 = Readonly<Info> & { userId: string }
interface PersonInfo4 extends Readonly<Info> {
    userId: string
}
let p: PersonInfo3 = {
    age: 22,
    name: 'Golang',
    userId: '5001011990203124'
}

p.age = 5 // Cannot assign to 'age' because it is a read-only property 
vaakian commented 2 years ago

Mapped Type(映射类型): keyof / in

keyof 获取一个interface / type的key列表的「联合类型」 in 遍历「联合类型」

in 例子

type Keys = "firstName" | "lastName"

type Person = {
    [key in Keys]: string
}
// 会得到以下类型
type Person = {
    firstName: string;
    lastName: string;
}

keyof例子

type Person = {
    name: string
    age: number
    sex: "男" | "女"
}
// Person2是一个映射类型,与Person的效果一样
type Person2 = {
    [P in keyof Person]: Person[P]
}

keyof Person拿到一个关于Personkey列表联合类型 "name" | "age" | "sex" 然后通过in遍历这个列表,又通过Person[P]拿到键PPerson中对应的类型。

可以看到,上面创建的Person2与Person的效果并无差别。所以有什么用呢? 以下是可以用到的例子:

// 让类型T的所有属性只读
type MyReadonly<T> = {
    readonly [prop in keyof T]: T[prop]
}
// 让类型T的所有属性可选
type MyOptional<T> = {
    [prop in keyof T]?: T[prop];
}
let p1: MyReadonly<Person> = {
    name: 'Xwj',
    age: 22,
    sex: '男'
}
p1.age = 23 // Cannot assign to 'age' because it is a read-only property

let p2: MyOptional<Person> = {
    name: 'Xwj',
    age: 22
} // 不赋值sex也不会报错

⚠️注意: 通过in来"映射"的类型不能再重新定义其他属性。会报以下错误。

A mapped type may not declare properties or methods 映射类型不能声明属性或方法

type Person2 = {
[P in keyof Person]: Person[P];
personId: string // A mapped type may not declare properties or methods
}

但是可以通用&创建一个交叉类型实现类似需求。

type Person2 = {
[P in keyof Person]: Person[P];
} & { personId: string }
vaakian commented 2 years ago

交叉类型(Intersection Types) / 联合类型(Union Types)

交叉类型

交叉类型通过&运算符来创建,尝试将两边的类型进行合并操作。

例子:

// 给Person类型新增了personId属性
type Person3 = Person & { personId: string }

而遇到冲突/重复键时,该属性就会被识别为never类型,也就是不可能出现的值类型。

下面例子的Person3的age属性为never类型,因为不可能出现即是number又是string类型的值。

type Person3 = Person & { age: string }

// 更简单的例子
type age = number & string

联合类型

联合类型通过 |运算符创建,像编程语言的运算,返回的类型语意为多个类型的其中之一。 通常用来约束变量值在某一个列表中。


// 表明age可能是string也可能是age
type age = number | string

// 实际用途

type Rank = "优秀" | "良好" | "及格" | "不及格"

let rank: Rank = "棒棒的" // Type '"棒棒的"' is not assignable to type 'Rank'
vaakian commented 2 years ago

never / void

never表示没有类型, 而void表示空类型,早期版本void类型包含nullundefined,而目前最新版只能是undefined

在以下两种情况会用到never类型。

// 抛出错误
function throwError(errorMsg: string): never { 
            throw new Error(errorMsg);
} 
// 无限循环
function keepProcessing(): never { 
      while (true) { 
         console.log('infinite loop!')
     }
}

在函数能够正常结束,但没有返回值或者返回undefined的情况下,可以用void类型。

function func1(): void {
    return undefined
}
function func2(): void {
    // no return 
}
function func3(): void {
    return void 0
}

冷知识: 如果需要一个undefined值,最好不要直接用undefined,因为undefined是一个全局变量,可能会被更改导致程序预期不一致。 void 0、void 任何值,它们的返回值都为undefined,而void 0最短,一般用它来创建一个undefined值。

vaakian commented 2 years ago

其它built-in泛型

Pick

Record

Extract

Exclude

Omit

see more

vaakian commented 2 years ago

类型定义文件(Type Declaration File)

在TypeScript中有两种文件格式,.ts格式包含类型定义和可执行代码,而.d.ts文件仅包含类型定义,仅用于类型检查(Type Checking),不会被编译成js文件。

在同一个项目中定义的类型名称不可重复,因为在默认情况下它们都属于同一个全局模块。解决办法是在子文件内使用export语句,那么会它创建一个本地作用域。


// some code
vaakian commented 2 years ago

模块查找

image

vaakian commented 2 years ago

模块声明 (module declarations)

https://ts.xcatliu.com/basics/declaration-files.html#declare-module