TypeScript 玩转类型操作之基础篇(回来,不是讲基础类型)
引言
本文的目的是探索 TypeScript 类型操作的基础知识,先介绍 typeof 、keyof、extends、infer 等操作关键词的使用方式(作为基础);然后介绍TS提供的通用类型工具(详细介绍官方源码具体实现);这两个部分熟练掌握,我们就掌握TS体操的核心内容了,剩下的就是考虑根据类型目标情况如何选择类型操作顺序。欢迎成为体操小能手~
typeof
typeof 在 JS 中用于获取一个变量的基础数据类型,在 TS 中 typeof 用于获取运行时变量或者属性的类型。在TS代码中需要注意这两种用法之间的差异,使用的情况不同的语义环境下有不能的表现形式。
typeof 以JS的判断变量类型时工作时,返回值是一个字符串内容是其中之一("string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
)。
const s = "hello";
let n = typeof s; // n 值是 "string",n 类型是 let n: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
let m: typeof s; // let m: stringconst s = "hello";
let n = typeof s; // n 值是 "string",n 类型是 let n: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
let m: typeof s; // let m: string
typeof 作为TS访问运行时值读取类型时,这个类型经过读取 type context 进行类型推导得出【返回的是一个TS的类型值,内容来自:自定义的类型修饰、无类型修饰时默认推导类型、强制类型转换后的类型结果】。
const point = {
x:1,y:1 };
// 没有指定类型,TS 默认类型推理推导出合适类型
type PointType = typeof point;
/* 等价于
type PointType = {
x: number;
y: number;
}
*/
const person = {
name: 'xxx' } as any;
// as 强制类型转换为 any, 使用强制类型转化的类型作为结果
type PersonType = typeof person;
// 等价于 type PersonType = any
type Car = {
drive: ()=>void;
name?: string;
}
const car: Car = {
drive:()=>{
} }
// 使用了指定的类型作为修饰,结果返回类型为指定的类型
type CarType = typeof car;
/* 等价于
type CarType = {
drive: () => void;
name?: string | undefined;
}
*/const point = {
x:1,y:1 };
// 没有指定类型,TS 默认类型推理推导出合适类型
type PointType = typeof point;
/* 等价于
type PointType = {
x: number;
y: number;
}
*/
const person = {
name: 'xxx' } as any;
// as 强制类型转换为 any, 使用强制类型转化的类型作为结果
type PersonType = typeof person;
// 等价于 type PersonType = any
type Car = {
drive: ()=>void;
name?: string;
}
const car: Car = {
drive:()=>{
} }
// 使用了指定的类型作为修饰,结果返回类型为指定的类型
type CarType = typeof car;
/* 等价于
type CarType = {
drive: () => void;
name?: string | undefined;
}
*/
typeof 的作用就是从JavaScript运行时变量值上提取出对应的TS类型,在 TS 体操中它是基础的类型操作。和 keyof 、 Omit、Partial、Record 等搭配起来非常好用。常用于:类型收窄(读取运行时特定字段的类型,用于判断)做类型守卫。
keyof
keyof 用于提取一个对象类型的属性名,返回一个字符串或数字字面量的联合类型。只有一个属性时返回字符串,多个属性时返回联合类型 ( 'xx' | 'yy'
),映射类型或条件类型下返回值会携带特殊的类型联合值。
普通对象类型 keyof 提取属性,interface 也能正常提取。注意不要对普通类型【string、number、联合类型等】使用 keyof 。
const point = {
x:1,y:1 };
type PointType = typeof point;
const person = {
name: 'xxx' } as any;
type PersonType = typeof person;
type PointKeysType = keyof PointType;
// 等价于 type PointKeysType = "x" | "y"
const point = {
x:1,y:1 };
type PointType = typeof point;
const person = {
name: 'xxx' } as any;
type PersonType = typeof person;
type PointKeysType = keyof PointType;
// 等价于 type PointKeysType = "x" | "y"
映射类型使用 keyof 时提取不到属性,此时默认返回可以作为对象属性值的类型联合 string | number | symbol
。映射类型为每个属性指定同样的类型,一般用于同一类型的注册表对象类型定义。
type ToolsType = {
[k:string]: Function
}
type ToolsKeys = keyof ToolsType; // string | number
// 将一个类型T上的所有属性值作为新类型的 key 构建新类型
type OptionsFlags<T> = {
[k in keyof T]: boolean
}
type CarOpFlag = keyof OptionsFlags // 这里写法不好,只做个演示。 等价于:type CarOpFlag = string | number | symbol
type ToolsType = {
[k:string]: Function
}
type ToolsKeys = keyof ToolsType; // string | number
// 将一个类型T上的所有属性值作为新类型的 key 构建新类型
type OptionsFlags<T> = {
[k in keyof T]: boolean
}
type CarOpFlag = keyof OptionsFlags // 这里写法不好,只做个演示。 等价于:type CarOpF