一、操作对象类型 Partial 将 T 的所有属性变为可选。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 interface User { name: string ; age: number ; email: string ; } type MyPartial<T> = { [P in keyof T]?: T[P] };type PartialUser = Partial<User>;function updateUser (id: number , fields: Partial<User> ) { } updateUser(1 , { name : 'Alice' });
Required 将 T 的所有属性变为必选(去掉 ?)。
1 2 3 4 5 6 7 8 9 10 type MyRequired<T> = { [P in keyof T]-?: T[P] };interface Config { debug?: boolean ; logLevel?: string ; } type StrictConfig = Required<Config>;
Readonly 将 T 的所有属性变为只读。
1 2 3 4 5 type MyReadonly<T> = { readonly [P in keyof T]: T[P] };type ReadonlyUser = Readonly<User>;
Pick<T, K> 从 T 中选取一组属性 K 组成新类型。
1 2 3 4 5 6 7 8 type MyPick<T, K extends keyof T> = { [P in K]: T[P] };type UserName = Pick<User, 'name' | 'email' >;type PublicUser = Pick<User, 'name' >;
Omit<T, K> 从 T 中排除一组属性 K,保留剩余属性。
1 2 3 4 5 type MyOmit<T, K extends keyof T> = { [P in Exclude<keyof T, K>]: T[P] };type UserWithoutPassword = Omit<User, 'password' | 'secret' >;
Record<K, T> 以 K 为键、T 为值构造一个对象类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 type MyRecord<K extends keyof any , T> = { [P in K]: T };type Page = 'home' | 'about' | 'contact' ;type PageInfo = Record<Page, { title : string ; url: string }>;const pages: PageInfo = { home: { title : '首页' , url : '/' }, about: { title : '关于' , url : '/about' }, contact: { title : '联系' , url : '/contact' }, }; const StatusMap: Record<number , string > = { 0 : 'pending' , 1 : 'active' , 2 : 'disabled' , };
二、操作联合类型 Exclude<T, U> 从 T 中排除可赋值给 U 的类型。
1 2 3 4 5 type MyExclude<T, U> = T extends U ? never : T;type T0 = Exclude<'a' | 'b' | 'c' , 'a' >; type T1 = Exclude<string | number | (() => void ), Function >;
从 T 中提取可赋值给 U 的类型。
1 2 3 4 5 type MyExtract<T, U> = T extends U ? T : never ;type T2 = Extract<'a' | 'b' | 'c' , 'a' | 'f' >; type T3 = Extract<string | number , number >;
NonNullable 从 T 中排除 null 和 undefined。
1 2 3 4 type MyNonNullable<T> = T extends null | undefined ? never : T;type T4 = NonNullable<string | number | null | undefined >;
三、操作函数类型 ReturnType 获取函数类型的返回值类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type MyReturnType<T extends (...args: any ) => any > = T extends (...args: any ) => infer R ? R : never ; type Fn = () => { a : number ; b: string };type T5 = ReturnType<Fn>; function fetchUser ( ) { return Promise .resolve({ id : 1 , name : 'Alice' }); } type FetchUserReturn = ReturnType<typeof fetchUser>;type UserData = Awaited<ReturnType<typeof fetchUser>>;
Parameters 获取函数类型的参数类型(元组)。
1 2 3 4 5 6 7 8 9 type MyParameters<T extends (...args: any ) => any > = T extends (...args: infer P) => any ? P : never ; type Fn2 = (name: string , age: number ) => void ;type T6 = Parameters<Fn2>; type FirstParam<T> = T extends (arg: infer P, ...rest: any ) => any ? P : never ;type T7 = FirstParam<Fn2>;
ConstructorParameters 获取构造函数类型的参数类型。
1 2 3 4 5 6 7 type T8 = ConstructorParameters<typeof Date >;function factory <T >(ctor: new (...args: any []) => T, ...args: ConstructorParameters<typeof ctor> ) { return new ctor(...args); }
InstanceType 获取构造函数类型的实例类型。
1 2 3 4 5 class MyClass { constructor (public name: string ) {} } type T9 = InstanceType<typeof MyClass>;
四、操作字符串类型 Uppercase / Lowercase / Capitalize / Uncapitalize 1 2 3 4 5 6 7 8 9 10 11 type T10 = Uppercase<'hello' >; type T11 = Lowercase<'HELLO' >; type T12 = Capitalize<'hello' >; type T13 = Uncapitalize<'Hello' >; type EventName = 'click' | 'mouseenter' | 'scroll' ;type Handlers = `on${Capitalize<EventName>} ` ; type CorrectHandler = `on${Capitalize<EventName>} ` ;
五、高级实用类型 Awaited<T 递归解包 Promise 类型(TS 4.5+)。
1 2 3 type T14 = Awaited<Promise <string >>; type T15 = Awaited<Promise <Promise <number >>>; type T16 = Awaited<Promise <string | number >>;
ThisParameterType / OmitThisParameter 1 2 3 4 5 6 function toHex (this : Number ) { return this .toString(16 ); } type T17 = ThisParameterType<typeof toHex>; type T18 = OmitThisParameter<typeof toHex>;
六、面试题 Q1: 如何让 Pick 支持嵌套路径? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 type NestedPick<T, K extends string > = K extends `${infer Key} .${infer Rest} ` ? Key extends keyof T ? { [P in Key]: NestedPick<T[Key], Rest> } : never : K extends keyof T ? { [P in K]: T[K] } : never ; type UserDeep = { profile: { name : string ; age: number }; settings: { theme : string }; }; type PickedUser = NestedPick<UserDeep, 'profile.name' >;
Q2: 实现 DeepReadonly 1 2 3 4 5 6 7 type DeepReadonly<T> = { readonly [P in keyof T]: T[P] extends object ? T[P] extends Function ? T[P] : DeepReadonly<T[P]> : T[P]; };
Q3: 从联合类型中排除函数类型 1 2 3 4 type ExcludeFunction<T> = T extends (...args: any ) => any ? never : T;type Mixed = string | number | (() => void ) | (() => string );type WithoutFn = ExcludeFunction<Mixed>;
Q4: Pick 和 Omit 的区别在面试中如何回答 1 2 3 4 5 6 7 8 Pick<T, K>:从 T 中选取 K 属性集合组成新类型,K 必须为 T 的 key。 Omit<T, K>:从 T 中排除 K 属性集合,保留剩余属性。 两者互补:Omit<T, K> = Pick<T, Exclude<keyof T, K>>。 适用场景: Pick → 接口响应中只暴露部分字段给前端 Omit → 排除敏感字段(密码、token)
Q5: 实现一个类型安全的状态机 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 type StateMachine<S extends string , E extends string > = { initial: S; states: Record<S, { on: Partial<Record<E, S>>; }>; }; const machine: StateMachine<'idle' | 'loading' | 'success' , 'FETCH' | 'RETRY' > = { initial: 'idle' , states: { idle: { on : { FETCH : 'loading' } }, loading: { on : { FETCH : 'loading' , RETRY : 'loading' } }, success: { on : { FETCH : 'loading' } }, }, };