基础类型
boolean、number、string、数组、元组、枚举、any、void、null、undefined、never、object
# boolean
let isDone: boolean = false;
# number
let decLiteral: number = 6;
# string
let name: string = "bob";
# 数组
let list: number[] = [1, 2, 3];
# 元组
let x: [string, number];
# 枚举
enum Color {Red, Green, Blue}
let c: Color = Color.Green;
# any
let notSure: any = 4;
notSure = "maybe a string instead";
# unknown
表示未知类型的值
let e: unknown;
e = 10
e = 'abc'
// unknown和any的区别在于:any类型的变量可以赋值给任意变量,unknown类型的变量不能直接赋值给其他变量
let s: string
if(typeof e === "string"){
s = e;
}
# void
function warnUser(): void {
console.log("This is my warning message");
}
# null 和 undefined
let u: undefined = undefined;
let n: null = null;
# never `never`类型表示的是那些永不存在的值的类型
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 一般在类型计算中使用比较多
# object `object`表示非原始类型
declare function create(o: object | null): void;
create({ prop: 0 }); // OK
create(null); // OK
create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error
字面量类型
type Str = 'abc'
类型断言
let someValue1: any = "this is a string";
let strLength1: number = (<string>someValue1).length;
let someValue2: any = "this is a string";
let strLength2: number = (someValue2 as string).length;
联合类型
联合类型表示一个值可以是几种类型之一
type UN = number | string | boolean
type TXT = 'A' | 'B'
交叉类型
type Interface1 = {
id: number;
name: string;
}
type Interface2 = {
age: string;
}
// 多个type交叉计算,得到所有类型的属性组成的新类型
type IntersectionType = Interface1 & Interface2;
{
id: number;
name: string;
age: string;
}
-------------------------------------------
type Interface1 = {
id: number;
name: string;
}
type Interface2 = {
id: string;
}
// 多个type交叉计算,得到所有类型的属性组成的新类型,如果有相同属性,则同名属性类型进行计算
type IntersectionType = Interface1 & Interface2;
{
id: never;
name: string;
}
类型语法基础
类型的条件判断
ts 类型的条件判断的语法是 条件 ? 分支1 : 分支2
type isNumber<T> = T extends number ? true : false
type res1 = isNumber<1> // true
type res2 = isNumber<'1'> // false
类型的遍历
type Person = {
name: string
age: number
}
type KeyofPersion = keyof Person // 'name' | 'age'
k in keyof Person
infer 类型变量
type Str<T extends string> = T extends `${infer Key}=${infer Value}`
? {
[k in Key]: Value
}
: never
索引类型
所谓的”索引类型“,就是用一个类型的所有字段名,组成一个字面量类型
type Person = {
name: string
age: number
}
映射类型
映射类型就是用于构造新的索引类型
type Record<K extends string | number | symbol, T> = {
[P in K]: T;
}
// 将索引类型的key变为只读
type Readonly<T> = {
readonly [Key in keyof T]: T[Key];
}
// 将索引类型的key变为可选
type Partial<T> = {
[Key in keyof T]?: T[Key]
}
// 将索引类型的key变为必选
type Required<T> = {
[Key in keyof T]-?: T[Key]
}
重映射
重映射就是在索引后加一个 as 语句,表明索引转换成什么,它可以用来对索引类型做过滤和转换 比如过滤出类型为 string 的索引: 返回 never 代表过滤掉,否则保留
type FilterString<T> = {
[Key in keyof T as T[Key] extends string ? Key: never]: T[Key];
}
还可以对索引做转换,比如修改索引名
type Getters<T extends Record<any, any>> = {
[Key in keyof T as `get${Capitalize<Key & string>}`]: T[Key];
}
模式匹配
字符串利用正则可以做模式匹配,例如:
'abc'.replace(/a(b)c/, '$1,$1,$1') // 'b,b,b'
Typescript 的类型也同样可以做模式匹配
type GetValueType<T> = T extends Promise<infer R> ? R : never
type PromiseType = Promise<string[]>
type Result = GetValueType<PromiseType>
// Result = string[]
我们通过 extends 对传入的类型参数 T 做模式匹配,其中 value 部分是需要提取的,通过 infer 类声明一个局部变量 R 来保存,如果匹配,就返回匹配到的 R,否则就返回 never 代表没匹配到
模式匹配应用场景
trim 是去掉前后的空格、制表符、换行符,那么就通过模式匹配取出后面的字符,通过 infer 放入新的变量返回就行
type LeftTrim<Str extends string> =
Str extends `${' ' | '\t' | '\n'}${infer Rest}`
? LeftTrim<Rest> : Str
type RightTrim<Str extends string> =
Str extends `${infer Rest}${' ' | '\t' | '\n'}`
? RightTrim<Rest> : Str
type Trim<Str extends string> = RightTrim<LeftTrim<Str>>
type res = Trim<' abc '>
//计算后结果:
获取函数参数类型和返回值类型
type GetParams<Func extends Function> = Func extends (
...params: infer Params
) => any
? Params
: never
type res = GetParams<(a: number, b: string) => void>
// 计算后结果:
type GetReturnType<Func extends Function> = Func extends (
...params: any
) => infer R
? R
: never
type res = GetReturnType<(a: number, b: string) => Promise<number>>
// 计算后结果:
类型计算示例
实现一个ParseQueryString,要求输入"a=1&a=2&b=3&d=4", 输出
{ a: ["1","2"], b: "3", d: "4" }
- 首先定义ParseQueryString,判断传入类型是否为 “&” 拼接格式的字面量类型,用第一个匹配到的 “&” 符号分割,第一部分为 "a=1" 格式, 使用 ParamString 处理,“&”后面的部分通过递归继续处理, 并使用MergeParams 合并数据
type ParseQueryString<Str extends string> =
Str extends `${infer Param}&${infer Reset}`
? MergeParams<ParamString<Param>, ParseQueryString<Reset>>
: ParamString<Str>
- 将匹配到的 "a=1" 形式的字面量类型处理为对象形式的索引类型 { "a" : "1" }
type ParamString<Str extends string> = Str extends `${infer Key}=${infer Value}`
? {
[K in Key]: Value
}
: object
3 .将ParamString处理好的类型合并为一个索引类型
type MergeParams<OneParams extends object, OtherParam extends object> = {
[Key in keyof OneParams | keyof OtherParam]: Key extends keyof
? Key extends keyof OtherParam
? MergeValue<OneParams[Key], OtherParam[Key]>
: OneParams[Key]
: Key extends keyof OtherParam
? OtherParam[Key]
: never
}
- 如果遇到key相同的值,则处理成数组格式
type MergeValue<One, Other> = One extends Other
? One
: Other extends unknown[]
? [One, ...Other]
: [One, Other]
type s = ParseQueryString<'a=1&a=2&b=3&c=4'>