ts的映射类型与keyof

494 阅读1分钟

TypeScript 给 JavaScript 加了套静态类型系统。其中,JavaScript 中的数组、对象等聚合多个元素的类型在 TypeScript 中对应的是索引类型。

1、映射类型

// 映射类型语法
// { readonly [P in K]?: T}

// { [P in K]: T}
// { [P in K]?: T}
// { [P in K]-?: T}
// { readonly [P in K]: T}
// { readonly [P in K] ?: T}
// { -readonly [P in K] ?: T}

//映射类型示例
type Item = { a: string; b: number; c: boolean; };

type T1 = { [P in 'x' | 'y']: number }; // {x: number; y: number}
type T2 = { [P in 'x' | 'y']: P }; // {x: ‘x' ; y: 'y'}
type T3 = { [P in 'a' | 'b']: Item[P] }; // {a: string ; b: number}
type T4 = { [P in keyof Item]: Item[P] }; // {a: string ; b: number, c: boolean}

2、实现工具类型

// 工具类型
type MyParital<T> = {
  [P in keyof T]?: T[P]
};
type U1 = MyParital<{ name: string; age: number }>;// { name?: string; age?: number }
//例子:生成对象KV类型的getter函数类型
type Getter<T> = {
  [K in keyof T as `get${Capitalize<K & string>}`]: () => T[K];
};

interface User {
  name: string;
  age: number;
  choose: boolean;
};

type Getter1 = Getter<User>;
// {
//   getName: () => string;
//   getAge: () => number;
//   getChoose: () => boolean;
// }
//例子:去除某一个key类型
type Exclude<T, K> = T extends K ? never : T;
type RemoveKindField<T> = {
  [K in keyof T as Exclude<K, 'kind'>]: T[K];
};

interface User2 {
  name: string;
  age: number;
  kind: 'kind'
};

type User3 = RemoveKindField<User2>;// {name: string; age: number}

3、keyof

keyof用法:

//keyof用法

// keyof用法示例
type K1 = keyof boolean; // 'valueof'
type K2 = keyof any;// string | number | symbol
type K3 = keyof number;// "toFixed" | "toExponential" | "toPrecision" | "toString" | "valueOf" | "toLocaleString"
type K4 = keyof string; // "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | ... 28 more ... | "valueOf"


enum HttpMethods {
  Get,
  Post,
  Put,
  Delete
};

type K5 = keyof typeof HttpMethods;// "Get" | "Post" | "Put" | "Delete"

Partial、Required、Pick、Record工具类型的内在实现

// 基于keyof实现的Partial、Required、Pick、Record工具类型的内在实现
type Partial<T> = {
  [K in keyof T]?: T[K]
};

type Required<T> = {
  [K in keyof T]-?: T[K];
}

type Pick<T, U extends keyof T> = {
  [K in U]: T[K]
};

type Record<T extends keyof any, U> {
  [key: T]: U;
}

keyof在泛型函数中的典型应用

type user5 = {
  name: string;
  age: number;
  boo: boolean;
}
type ValueType<T, U> = T extends keyof U ? U[T] : never;
function fn3(obj: user5, key: keyof user5): ValueType<keyof user5, user5> {
  return obj[key];
}

比如我们把一个索引类型的值变成 3 个元素的数组:
type MapType<T> = { 
    [Key in keyof T]: [T[Key], T[Key], T[Key]] 
} 
type res = MapType<{a: 1, b: 2}>;
/*
type res={
    a:[1,1,1];
    b:[2,2,2};
}
*/

除了值可以变化,索引也可以做变化,用 as 运算符,叫做重映射

type MapType<T> = { 
    [ 
        Key in keyof T as `${Key & string}${Key & string}${Key & string}` 
    ]: [T[Key], T[Key], T[Key]] 
}
/*
type res={
    aaa:[1,1,1];
    bbbb:[2,2,2};
}
这里的 & string 可能大家会迷惑,解释一下:
因为索引类型(对象、class 等)可以用 string、number 和 symbol 作为 key,这里 keyof T 取出的索引就是
string | number | symbol 的联合类型,和 string 取交叉部分就只剩下 string 了。就像前面所说,交叉类型
会把同一类型做合并,不同类型舍弃。
*/

原文链接:

blog.csdn.net/qq_48896417…