TypeScript概要
JavaScrip编译与运行的流程大致如下:
第一步:把程序解析为AST(去掉空白、注释、制表符、空格等) 第二步:把AST编译成字符码 第三步:运行时计算字节码
TypeScript编译与运行的流程大致如下:
第一步:把TypeScript源码解析为AST 第二步:类型检查器检查AST 第三步:把TypeScript AST解析为JavaScript源码 第四步:把JavaScript源码解析为JavaScript AST 第五步:把AST编译成字节码 第六步:运行时计算字节码
TypeScript中的类型对程序输出没有任何影响,类型只在类型检查这一步使用
TypeScript是以JavaScript为基础构建的语言,也称为JavaScript的超集。 TypeScript扩展了JavaScript,并添加了类型。 TypeScript可以在任何支持JavaScript的平台中运行,由于无法直接执行,需要使用插件编译为JavaScript。
TypeScript基础
类型操作
1. 类型系统
TypeScript类型系统分为以下两种:
- 通过显式句法告诉编译器所有值的类型
- 自动推导值的类型
最好让TypeScript推导类型,少数情况下才显式注解类型
| 类型系统特性 | JavaScript | TypeScript |
|---|---|---|
| 类型是如何绑定的? | 动态 | 静态 |
| 是否自动转换类型? | 是 | 否(多数情况下) |
| 何时检查类型? | 运行时 | 编译时 |
| 何时报告错误? | 运行时(多数情况下) | 编译时(多数情况下) |
2. 类型全解
| 类型 | 举例 | 描述 |
|---|---|---|
| number | 1、2、-10 | 任意数字 |
| string | 'hellow'、'123' | 任意字符串 |
| boolean | true、false | 布尔值 |
| 字面量 | 其本身 | 限制变量的值即为字面量的值 |
| any | * | 任意类型 |
| unknown | * | 类型安全的any |
| Function | function fn(f:Function){ return f(1,2,3); } | 函数类型,可以调用bind、call等API |
| void | 空值(undefined) | 无值或undefined |
| never | 无值 | 不能是任何值 |
| object | {name:'小明',age:25} | 任意的JS对象 |
| array | [1,2,3] | 任意的JS数组 |
| tuple | [4,5] | 元素类型可以不同,TS新增类型,固定长度的数组 |
| enum | enum{A,B} | 枚举,TS新增类型 |
1)字面量:仅表示一个值的类型
let b: "male" | "female"; // 只能是male或者female
b = "male";
b = "female";
字面量类型支持模版拼接
type Direction = 'left' | 'right' | 'top' | 'bottom';
type marginDirection = `margin-${Direction}`;
type paddinngDirection = `padding-${Direction}`;
2)any:表示的是任意类型(类似类型教父),一个变量设置类型any 后相当于对该变量关闭了TS 的类型检测,any类型可以赋值给任意类型变量
let d: any;
let d;
3)unknown:表示未知类型,不能赋值给其他类型变量,当无法预知一个值的类型时使用。
注意⚠️:TypeScript不会把任何值推导为unknown类型,必须显式注解;unknown类型的值可以进行比较;不能假定unknown类型的值为某一特定类型,必须先向TypeScript证明一个值明确是某个类型
let d: unknown
4)void:表示无返回值
function fn():void{}
5)never:表示永远不会返回结果,包括不会返回undefined
function fn():never{
throw new Error('程序运行错误');
}
function fn():never{
while(true){
doSomething();
}
}
6)tuple:固定长度,各索引位上的值具有固定的已知类型
注意⚠️:元组支持可选元素和剩余元素
let t: [string, number, object, boolean] = ['h',1,{},true];
let t: [string, number, object, boolean?] = ['h',1,{}];
let t: [string, ...string[]] = ['h','e'];
7)enum:列举类型中包含的各个值,是一种无序的数据结构,把键映射到值上。
枚举分为两类:字符串到字符串之间的映射、字符串到数字之间的映射。
TypeScript可以自动为枚举中的各个成员推导对应的数字,也可以手动设置。
enum Gender {
Male = 0,
Female = 1
}
注意⚠️:一个枚举可以分为多次声明,TypeScript可以自动把各个部分合并在一起,但是却只能推导出其中一部分的值
3. 索引签名
[key: T]: U
索引签名的意思是“在这个对象中,类型为T的键对应的值为U类型”。
键的类型(T)必须可赋值给number或string或symbol
适用场景:显示声明键的类型、添加更多的键
class MyClass {
// 属性名是字符串类型,属性值可以使布尔值,也可以是函数
[s: string]: boolean | ((s: string) => boolean);
// 参数为字符串类型,返回值
check(s: string) {
return this[s] as boolean;
}
}
// 使用
class MyClass {
x = true;
}
键的类型不能是字面量类型或泛型类型
type D = {
[K:'id']: string; // error
}
4. 类型声明
类型声明是TS非常重要的一个特点,通过类型声明可以指定TS中变量 (参数、形参) 的类型。
指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明。如果符合则赋值,否则报错。
let 变量: 类型;
let 变量: 类型 = 值;
function fn(参数: 类型,参数: 类型): 类型{... ...}
TS拥有自动的类型判断机制,当对变量的声明和赋值同时进行时,TS编译器会自动判断变量的类型。
let a:number = 10;
a = '10'; // ts:不能将类型“string”分配给类型“number”
5. 类型别名
作用:为类型声明一个别名
type Point = { x:number, y:string };
type IDType = number | string;
// 使用别名
function fn(id:IDType):void{};
扩展类型:&
// 扩展
type Animal = { name: string };
type Bear = Animal & { honey: boolean };
// 使用
const bear:Bear = { name: 'winnie', honey: true }
不允许添加字段:
type Animal = {
name: string;
}
type Animal = { // ts Error:标识符“Animal”重复。
age: number;
}
注意⚠️:
type声明类型时,不能通过对同一标识符重复声明的方式添加类型;
TypeScript无法推导类型别名,因此必须显式注解;
类型别名采用块级作用域,内部的类型别名将遮盖外部的类型别名;
内置映射类型Pick、Partial、Record、Required等都是以type定义的
6. 联合类型
声明变量为一个或者多个其他类型组成的集合
let b: string | number // b可以是字符串类型或者数值型
适用场景:某个变量或者参数的类型不确定,可以是多个类型时使用。
function welcomePeople(x: string[] | string){
if (Array.isArray(x)) {
console.log('Hello, ' + x.join('and'));
}else{
console.log( 'Welcome lone traveler' + x);
}
}
注意⚠️:如果需要使用某个特定类型的原生API时,需要对类型进行判断,否则会抛出错误。类型判断的方法包括JS中的typeof、toString、instanceOf、Array.isArray等。
7. 类型断言
某些情况下TS编译对于变量的类型不确定,此时可以通过类型断言来告诉编译器变量的类型
第一种形式:value as 类型
let somevalue: unknown = "this is a string";
let strLength: number = (somevalue as string).length;
第二种形式: <类型>value
let somevalue: unknown = "this is a string";
let strLength: number = (<string> somevalue).length;
8. 接口
作用:声明类型的一种方式,可以定义一个公共的类型供重复使用
interface Point {
x: number;
y: number;
}
function printCoord(pt: Point) {
console.log ("坐标x的值是. " + pt.x);
console.log("坐标y的值是" + pt.y);
}
printCoord({ x: 100, y: 100 });
扩展接口:extends
// extends 关键字扩展接口
interface Animal { name: string }
interface Bear extends Animal { honey: boolean }
// 使用
const bear: Bear = { name: 'winie', honey: true }
5)添加字段
// 向现有的类型添加字段
interface MyWindow { count: number };
interface MyWindow { title: string };
// 使用
const w: MyWindow = { title: 'hello', count: 100 };
6)类型别名与接口区别
第一:类型别名更为通用,可以是任何类型,包括类型表达式(类型、类型运算等);接口声明中必须是结构
第二:扩展接口时,TypeScript将检查扩展的接口是否可以赋值给被扩展的接口;重复声明同一个类型别名,TypeScript会报错
第三:同一个作用域中的多个同名接口将自动合并,类型别名则会直接报错
9. 类型守卫
1)适用场景
用于处理联合类型变量的场景,将类型范围缩小
类型防护:特殊类型的检查
类型缩小:将类型细化为比声明更具体的类型的过程
2)typeof类型守卫
typeof strs =
"object"
"string"
"number"
"bigint"
"boolean"
"symbol"
"undefined"
"function"
3)真值缩小
通过Boolean()方式可以将值转换为true或者false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
Boolean(null) // false
Boolean(undefined) // false
Boolean(0n) // false BigInt零的表示
通过!!方式也可以将值转换为true或者false
!!0 === false
!!NaN === false
!!'' === false
!!null === false
!!undefined ===false
!!0n === false
4)in操作符缩小
'value' in x(联合类型)
返回值为true:x具有可选或者必须属性的值
返回值为false:x具有可选或者缺失属性的值
type Fish = { swim: ()=>void };
type Bird = { fly: ()=>void };
type Human = { swim?: ()=>void; fly?: ()=>void }
function move(animal: Fish | Bird | Human){
if ("swim" in animal) { // 可能是Fish或者Human类型
return (animal as Fish).swim(); // 需要配合使用as,进行类型断言,否则报错
}
return (animal as Bird).fly();
}
5)instanceof操作符缩小
作用:检查一个值是否为某个类型实例
x instanceof FOO
返回值为true:x是FOO类型实例
返回值为false:x不是FOO类型实例
function logValue(x: Date){
if(x instanceof Date){
console.log(x.toLocalstring())
}else{
console.log(x.toUpperCase())
}
}
6)分配缩小
通过判断条件选择为某个变量赋不同的值,从而缩小变量类型范围
let x = Math random() < 0.5 ? 10 : 'hello world';
10. 类型谓词
作用:有效的根据条件缩小类型范围,和typeof、in、instanceof类似。
类型谓词采用parameterName is Type格式,其中parameterName 必须是当前函数中的参数名称。
function runner(params: null | undefined | string): void {
if (params === null) {
console.log('null');
} else {
console.log(params);
}
}
使用类型谓词优化条件判断
function isUndef (val: any): val is null | undefined {
return val == null;
}
function runner(params: null | undefined | string): void {
if (isUndef(params)) {
console.log('null');
} else {
console.log(params);
}
}
11. 交叉类型&
A & B表示将A类型和B类型合并,如果存在重复属性时,取重复属性中范围最大的那个(any和string则为any),如果重复属性没有交集则为never(string和number)
interface A {
name:string;
age:number;
}
interface B {
name:string;
school: string;
}
type C = A & B;
// type C = {name:string;age:number;school:string;}
function函数
1. 注解this类型
程序中this的值取决于调用函数的方式,而不受声明方式的干扰。如果函数中使用this,需要在函数的第一个参数中声明this的类型。
function greet(this:Array<number>){
return `${this.length}`;
}
greet.call([1]);
greet(); // Error
2. 调用签名
作用:表示函数类型的句法,没有函数的定义体,无法推导返回类型,必须显式注解
(a: number, b: number) => number
注意⚠️:调用签名中不再使用 =>,而是用“:”代替
type DescribableFunction = {
description: string;
(someArg: number): boolean
}
function doSomething(fn: DescribableFunction) {
console.log(fn.description + 'returned' + fn(6)); // 参数为函数类型,函数包括一个属性
}
function fn1(n: number) { // 创建函数类型
console.log(n);
return true;
}
fn1.description = "hello"; // 为函数添加属性
doSomething(fn1);
3. 重载签名
作用:根据参数数量不同,执行不同的逻辑主体,一般包括多个重载函数和一个实现函数。
如果函数有多个重载签名,在调用方看来,函数的类型是各个签名的并集。
// 重载函数签名
function makeDate (timestamp: number): Date;
function makeDate(m: number, d: number,y: number): Date;
// 实现函数签名,接收参数为1个或3个
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
if(d !== undefined && y !== undefined){
return new Date(y, mOrTimestamp, d);
}else{
return new Date(mOrTimestamp);
}
}
makeDate(123456);
makeDate(1,2,3);
注意⚠️:重载签名和实现签名的参数数量、参数类型、返回值类型需一致
⚠️:参数数量必须一致
function fn(x:string):void;
function fn(){}
⚠️:参数类型必须一致
function fn(x:string):void;
function fn(x:boolean):void;
function fn(x:string | boolean){};
⚠️:返回值类型必须一致
functionfn(x:string):string;
functionfn(x:boolean):boolean;
functionfn(x:string | boolean):string|boolean{
return true || '100';
}
注意⚠️:在可能的情况下,总是倾向于使用联合类型的参数而不是重载参数
function fn(x:string):string;
function fn(x:boolean):boolean;
function fn(x:string | boolean):string|boolean{
return '100';
}
fn(Math.random() > 0.5 ? '123' : true) // Error
// 使用联合类型代替函数重载签名
function fn(x:string | boolean):string|boolean{
return '100';
}
fn(Math.random() > 0.5 ? '123' : true)
4. 构造签名
class Ctor {
s: string;
constructor(s: string) {
this.s = s
}
}
type SomeConstructor = {
new (s: string): Ctor
}
function fn(ctor: SomeConstructor){
return new ctor('hello');
}
class类
1. 类的静态属性
class Artical {
title: string; // 必须属性
content: string;
data?: string; // 可选属性
level = 3 // 属性默认值
constructor(title:string,content:string){
this.title = title;
this.content = content;
}
}
const artical1 = new Artical('国家地理', '酸酸臭臭一家亲');
2. 修饰符
- public:默认值,不写的时候就是public,任何对象在任何地方均可以访问
- private:私有的,只能在类中访问
- protected:受保护的,能在当前类和子类中访问,不能在实例中访问
- static:不需要实例化,可以直接通过类调用
class Greeter {
public greet() {
console.log("hi!");
}
private sun(){
console.log("sun");
}
protected sleep(){
console.log('sleep');
}
static eat(){
console.log('eat');
}
}
class Item extends Greeter {
constructor(){
super();
}
}
Greeter.eat(); // eat
const item = new Item();
item.greet(); // hi!
item.sun(); // Error
item.sleep(); // Error
注意⚠️:静态成员也可以使用public、protected、private修饰符;静态成员也可以被继承;
修饰符可以连用,static必须在其他修饰符后面,如public static name:string
- abstract:抽象类和属性及方法,规定子类必须具有,本身不会实例化
abstract class Animal {
abstract name:string;
}
class Dog extends Animal {
name = '胖胖'
}
3. super
作用:子类中可以使用super调用父类中的同名方法
适用场景:
- 方法调用:super.take
- 构造函数调用:super()
使用super只能访问父类中的方法,不能访问父类中的属性
4. 以this为返回类型
适用场景:以this注解返回值的类型,TypeScript会自动推导
type SetType = {
has: (value:number) => boolean,
add: (value:number) => this
}
5. implements
作用:指名该类满足某个接口
interface Animal {
eat(food:string):void;
sleep(hours:number):void;
}
// 满足单个接口
class Cat implements Animal {
eat(food:string){
console.log(`吃了${food}`);
};
sleep(hours: number): void {
console.log(`睡了${hours}小时`);
}
}
// 满足多个接口
class Cat implements Animal, Feline {}
6. 类的初始化顺序
Class Base {
name ="base";
constructor(){console.log("My name is " + this.name);
}
Class Derived extends Base {
name = 'derived';
}
const derived = new Derived(); // base
基类的字段被初始化 => 基类构造函数运行 => 派生类的字段被初始化 => 派生类构造函数运行
对象
1. 声明类型
interface person {
name:string;
age:number
}
type person = {
name:string;
age:number
}
2. 属性设置
interface person {
name:string; // 必传属性
sex?:string // 可选属性
readonly hony:string[] // 只读属性
}
type person = {
name:string; // 必传属性
sex?: string // 可选属性
}
readonly只能限制当前属性,并不能限制属性内部的其他属性,相当于浅只读
3. 索引签名
interface StringArray {
[index: number]: string,
[prop: string]: string,
readonly [index: number]: string
}
const myArray: StringArray = ['a','b'];
const seconditem = myArray[0];
4. 类型处理
1)扩展类型
interface person {
name:string;
age:number;
sex?:string
readonly hony:string[]
}
interface chinese {
china: string;
}
// 扩展单个类型
interface Femal extends person {
school: string
}
// 扩展多个类型
interface Femal extends person,chinese {
school: string;
}
2)交叉类型&
type Color ={
color:string;
}
type FontStyle = {
size:number;
}
type ColorAndFont = Color & FontStyle;
let c:ColorAndFont = {
color:'red',
size:200
}
类型操作
1. keyof
keyof T获取类型 T 的所有公共属性键,会返回一个联合类型,该联合类型包含 T 类型中所有可索引的公共属性名。
interface Person {
name: string;
age: number;
address?: string;
}
type PersonKeys = keyof Person;
// PersonKeys的类型是"name"|"age"|"address"
2. typeof
typeof用于获取给定表达式的类型,返回一个表达式类型的字符串。
typeof undefined // 'undefined'
typeof null // 'object'
typeof true // 'boolean'
typeof 1 // 'number'
typeof 'hello' // 'string'
typeof BigInt(1) // 'bigint'
typeof Symbol(1) // 'symbol'
typeof function a(){} // 'function'
将 typeof 与条件类型结合,我们可以在运行时对不同类型的代码进行条件分支。
function test (num: number | string): number | string {
if (typeof num === 'number') {
return ++num;
} else {
return +num + 1;
}
}
typeof也可以用于复杂类型判断。
const appconfig = {
id: 1,
text: 'app',
}
type appType = typeof appconfig // {id: number;text: string}
const appconfigtest: appType = {}
3. in
通过in生成映射类型,in可以理解为js中的for...in循环操作。
enum Letter {
A=a,
B=b,
C=c
}
type LetterMap = {
[key in Letter]:string
}
等价于
type _LetterMap={
a:string
b:string
c:string
}
项目中使用
type Item = {
a:string;
b:number;
c:boolean;
}
type T1 = {
[P in 'x' | 'y']:number;
}
// type T1 = { x: number; y: number; }
type T2 = {
[P in 'x' | 'y']: P
}
// type T2 = { x: "x"; y: "y"; }
type T3 = {
[P in 'a' | 'b']: Item[P]
}
// type T3 = { a: string; b: number; }
type T4 = {
[P in keyof Item]:Item[P]
}
// type T4 = { a: string; b: number; c: boolean; }
泛型
1. 泛型作用
当定义一个变量不确定类型的时候有两种解决方式:
- any:失去了TS类型保护的优势
- 泛型:泛型指的是在定义函数/接口/类型时,不预先指定具体的类型,而是在使用的时候再指定类型限制的一种特性
2. 泛型使用
函数中使用
function test <T> (arg:T):T{
console.log(arg);
return arg;
}
test<number>(111);// 返回值是number类型的 111
test<string | boolean>('hahaha')//返回值是string类型的 hahaha
test<string | boolean>(true);//返回值是布尔类型的 true
接口中使用
interface Search {
<T,Y>(name:T,age:Y):T
}
let fn:Search = function <T, Y>(name: T, id:Y):T {
console.log(name, id)
return name;
}
fn('li',11);//编译器会自动识别传入的参数,将传入的参数的类型认为是泛型指定的类型
类中使用
class Animal<T> {
name:T;
constructor(name: T){
this.name = name;
}
action<T>(say:T) {
console.log(say)
}
}
let cat = new Animal('cat');
cat.action('mimi');
尖括号的位置限定泛型的作用域,并且在一对尖括号中可以声明任意个以逗号分隔的泛型参数
3. 泛型约束
// 单个约束
T extends U
// 多个约束
T extends U & V & W
当Type类型无法确定,但又需要参数具有某个属性时,需要对Type进行限制,从而限制了参数的类型。
function longest<Type extends {length: number}>(a: Type, b: Type){
if (a.length >= b.length) {
return a;
}else{
return b;
}
}
const result = longest([1,2,3],[4,5]); // [1,2,3]
const longerString = longest('felix', 'lu') // 'felix'
const notok = longest(10,100) // 报错,number没有length属性
4. 泛型指定类型
由于使用泛型,TS会自动推断Type类型,当需要改变Type时,会报错。为了解决这个问题,需要使用指定函数参数的类型
function combine<T>(arr1: T[], arr2: T[]): T[] {
return arr1.concat(arr2);
}
const arr = combine(["string"],[1,2,3]) // TS会推断Type等于string
通过<>指定多个参数类型
const arr = combine<string | number>(["string"],[1,2,3])
注意⚠️
- 可能的情况下,使用类型参数本身,而不是对其进行约束
- 总是尽可能少地使用类型参数
- 如果一个类型的参数只出现在一个地方,请重新考虑你是否真的需要它
5. 泛型默认类型
type MyEvent<T = HTMLElement> = {
target: T,
type: string
}
注意⚠️:泛型默认类型需要放在没有默认类型的泛型之后
TypeScript进阶
extends
1. 继承
class Animal{
move(){
console.log("Moving along!");
}
}
class Person extends Animal{
talk(info){
console.log(info)
}
}
const person = new Person();
person.move();
person.talk('hello world')
2. 类型约束
interface ILength {
length: number
}
function id<Type extends ILength>(value: Type): Type {
console.log(value.length)
return value
}
3. 接口扩展
interface Animal {
name: string
}
interface Person extends Animal {
level: number
}
const person: Person = {
name: 'Perter',
level: 1
}
4. 条件类型判断
当T类型可以赋值给U类型时,则返回X类型,否则返回Y类型。
T extends U ? X : Y
TUXY四个是占位符,分别表示四种类型;T extends U表示T类型能被赋值给U类型,这里还涉及到TS类型兼容性
特殊类型兼容性判断:
any:any 可以赋值给除 never 以外的任何类型,任何类型都可以赋值给 anynever:never 可以赋值给任何类型,其他任何类型不能赋值给 neverunknown:unknow 只能赋值给 any 类型,其他任何类型都可以赋值给 unknown
比如工具类型 Exclude 的实现,就是基于条件类型
// 排除联合类型 `T` 中匹配的类型
type MyExclude<T, Key> = T extends Key ? never : T`
type T0 = MyExclude<"a"|"b"|"c","a">; // type T0 = "b"|"c"
type T1 = MyExclude<"a"|"b"|"c","a"|"b">; // type T1 = "c"
infer
在TypeScript中,infer是一个关键字,用于在条件类型中声明类型变量,存储在模式匹配过程中捕获的类型。
infer U 相当于引入一个新的变量U,并且可以在后续代码中捕获。
infer语句只能在extends子句中使用; infer声明的变量只能在条件分支中true时使用
1. 获取函数的返回值
目前TS已经提供了ReturnType<T>类型工具,如果传入函数类型则返回函数的返回值类型。
let r: ReturnType<() => number>
通过infer关键字也可以实现一个ReturnType<T>工具
type MyReturn<T> = T extends (...args: any[]) => infer U ? U : T
let r: MyReturn<number>
2. 获取数组元素的类型
type InferArray<T> = T extends Array<infer U> ? U : T
let r:InferArray<string>
3. 提取类型的部分属性为新类型
假设目前有一个类型,包含两个属性name和age,要求从Person类型中提取出只包含名字的子类型。
type Person = {
name: string;
age: number;
}
type ExtractName<T> = T extends { name: infer U; age: number } ? U : never;
type NameOnly = ExtractName<Person>;
内置条件类型
1. Exclude(排除)
Exclude<T, U>表示从T中剔除可以赋值给U的类型,如果 T 是 U 的子类型则返回 never,不是则返回 T。
type A = number | string | boolean
type B = number | boolean
type Foo = Exclude<A, B>
2. Extract(提取)
Extract<T, U>表示提取T中可以赋值给U的类型,和 Exclude 作用相反。
type A = number | string | boolean
type B = number | boolean
type Foo = Extract<A, B>
3. NonNullable
NonNullable<T>表示从T中剔除null和undefined。
// 源码
type NonNullable<T> = T extends null | undefined ? never : T;
// 使用
type t = NonNullable<'name' | undefined | null>;
4. ReturnType
ReturnType<T>表示获取函数返回值类型。
// 源码
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
// 使用
type t = ReturnType<(name: string) => string | number>
function getUser() {
return {name: 'xxx', age: 10}
}
type GetUserType = typeof getUser; // 获取函数类型
type ReturnUser = ReturnType<GetUserType> // 获取函数返回值类型
5. InstanceType
InstanceType<T>表示获取构造函数的实例类型。
// 源码
type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
// 使用
type t = InstanceType<new (name: string) =>{name:string,age:number}>
内置映射类型
1. Record
Record<K, V>创建一个对象类型,其中所有属性的键都是由 K 类型表示,值都是由 V 类型表示。
type Person = {
name:string,
age:number,
sex:'F' | 'M'
}
type UserMap = Record<string, Person>;
2. Partial(可选)
用于生成一个新类型,该类型与 T 拥有相同的属性,但是所有属性皆为可选项。
interface Foo {
name: string
age: number
}
type Bar = Partial<Foo>
// 源码
type MyPartial<T> = {
[P in keyof T]?:T[P]
}
3. Required(必须)
用于生成一个新类型,该类型与 T 拥有相同的属性,但是所有属性皆为必选项。
interface Foo {
name: string
age?: number
}
type Bar = Required<Foo>
4. Readonly(只读)
用于生成一个新类型,该类型与 T 拥有相同的属性,但是所有属性皆为只读不可修改。
interface Foo {
name: string
age: number
}
type Bar = Readonly<Foo>
5. Pick(选择)
用于生成一个新类型,该类型包含T中部分属性,所有属性均来源于keys。
interface Foo {
name: string;
age?: number;
gender: string;
}
type Bar = Pick<Foo, 'age' | 'gender'>
//源码
type Pick<T,K extends keyof T> = {
[P in K]: T[P];
}
6. Omit(省略)
用于生成一个新类型,该类型拥有 T 中除了 K 属性以外的所有属性。
type Foo = {
name: string;
age?: number;
gender: string;
}
type Bar = Omit<Foo, 'age' | 'gender'>
//源码
type Omit<T,K extends keyof any>=Pick<T, Exclude<keyof T, k>>
7. Parameters
用于以元组的方式获得函数的入参类型。
type t = Parameters<(name: string) => any>;
type t2 = Parameters<((name: string) => any) | ((age: number) => any)>;
8. ConstructorParameters
用于以元组的方式获得构造函数的入参类型。
type t = ConstructorParameters<(new (name: string) => any)|(new (age: number) => any)>;