[月分享] TypeScript - 常用内置类型与使用技巧


/**
 * keyof<T>
 *  获取一个对象接口的所有 key 值
 *  keyof 与 Object.keys 略有相似,只不过 keyof 取 interface 的键。
 */
() => {
  interface Person {
    name: string;
    age: number;
    location: string;
  }

  type K1 = keyof Person; // "name" | "age" | "location"
  type K2 = keyof Person[]; // "length" | "push" | "pop" | "concat" | ...
  type K3 = keyof { [x: string]: Person }; // string

  // 获取对象的属性
  function pluck<T, K extends keyof T>(o: T, names: K): T[K] {
    return o[names];
  }
};
(_tip: "keyof 只会返回不为 null undefined never 的类型") => {
  interface EnumType {
    a: never;
    b: undefined;
    c: null;
    d: number;
    e: object;
  }
  type TypeEnumType = keyof EnumType; // a | b | c | d | e
  type TypeEnumType1 = EnumType[keyof EnumType]; // number | object 去除了了3种假类型

  type ReadonlyType<T> = {
    readonly [P in keyof T]?: T[P];
  };
  let readOnly: ReadonlyType<EnumType> = {}; // 将 EnumType 所有类型都变为了了 只读
};

/**
 * Pick<T, K>
 *  从对象类型 T 挑选一些属性 K
 *  比如对象拥有 5 个 key,只需要将 K 设置为 "name" | "age" 就可以生成仅支持这两个 key 的新对象类型。
 */
() => {
  interface IObj {
    a: string;
    b: number;
    c: boolean;
  }
  type FilterObj = Pick<IObj, "a" | "b">;
  const test: FilterObj = {
    a: "str",
    b: 1,
  };
};

/**
 * Extract<T, U>
 *  挑选 key 中的 key
 *  Extract 是 Pick 的底层 API,直到 2.8 版本才内置进来,
 *  可以认为 Pick 是挑选对象的某些 key,Extract 是挑选 key 中的 key。
 */
() => {
  interface IObj {
    a: string;
    b: number;
    c: boolean;
  }
  type FilterKey = Extract<keyof IObj, "a">;
  const test: FilterKey = "a";
};

/**
 * Exclude<T, U>
 *  将 T 中的 U 类型排除,和 Extract 功能相反。
 */
() => {
  interface IObj {
    a: string;
    b: number;
    c: boolean;
  }
  type FilterKey = Exclude<keyof IObj, "a" | "b">;
  const test: FilterKey = "c";
};

/**
 * Record<K, U>
 *  将 K 中所有的属性的值转化为 U 类型
 *  ts文档上对Record的介绍不多,但却经常用到,Record是一个很好用的工具类型。
 *  他会将一个类型的所有属性值都映射到另一个类型上并创造一个新的类型
 */
(_tip: "源码") => {
  // 将K中的所有属性值都转换为T类型,并将返回的新类型返回给proxyKType,K可以是联合类型、对象、枚举
  type Record<K extends keyof any, T> = {
    [P in K]: T;
  };
};
(_tip: "Demo") => {
  interface AnimalsInfo {
    dog: {
      name: string;
      age: number;
    };
    cat: {
      name: string;
      age: number;
    };
  }
  const animalsInfo: AnimalsInfo = {
    dog: {
      name: "dogName",
      age: 2,
    },
    cat: {
      name: "catName",
      age: 3,
    },
  };
};
(_tip: "Demo1") => {
  type petsGroup = "dog" | "cat";
  interface IPetInfo {
    name: string;
    age: number;
  }
  type IPets = Record<petsGroup, IPetInfo>;
  const animalsInfo = {
    dog: {
      name: "dogName",
      age: 2,
    },
    cat: {
      name: "catName",
      age: 3,
    },
  };
};
(_tip: "Demo2") => {
  type petsGroup = "dog" | "cat";
  interface IPetInfo {
    name: string;
    age: number;
  }
  type IPets = Record<petsGroup | "otherAnamial", IPetInfo>;
  const animalsInfo: IPets = {
    dog: {
      name: "dogName",
      age: 2,
    },
    cat: {
      name: "catName",
      age: 3,
    },
    otherAnamial: {
      name: "otherAnamialName",
      age: 10,
    },
  };
};

/**
 * Omit<K, U>
 *  返回移除 K 对象中的 U 属性后的新类型
 */

(_tip: "源码") => {
  type Omit<T, K> = Pick<T, Exclude<keyof T, K>>
};
(_tip: "使用") => {
  type Foo = Omit<{name: string, age: number}, 'name'> // { age: number }
};


/**
 * 技巧
 *  数组类型明文确认长度
 */
before => {
  const data = [
    [1, 5.5],
    [2, 3.7],
    [3, 2.0],
    [4, 5.9],
    [5, 3.9],
  ];
};
after => {
  interface CharData extends Array<number> {
    0: number;
    1: number;
    length: 2;
  }
  const data2: CharData[] = [
    [1, 5.5],
    [2, 3.7],
    [3, 2.0],
    [4, 5.9],
    [5, 3.9],
  ];
};
(ts 3.0+) => {
  type Tuple<TItem, TLength extends number> = [TItem, ...TItem[]] & {
    length: TLength;
  };
  const data3: Tuple<number,2>[] = [
      [1, 5.5],
      [2, 3.7],
      [3, 2.0],
      [4, 5.9],
      [5, 3.9],
    ];
  tips: ts 3.0在元组类型中引入了其余元素
  // https://stackoverflow.com/questions/52489261/typescript-can-i-define-an-n-length-tuple-type
}

/**
 * 技巧
 *  巧用查找类型
 */
before => {
  interface Person {
    addr: {
      city: string;
      street: string;
      num: number;
    };
  }
  interface Address {
    city: string;
    street: string;
    num: number;
  }
  const Addr: Address = {
    city: "city",
    street: "street",
    num: 0,
  };
};
after => {
  interface Person {
    addr: {
      city: string;
      street: string;
      num: number;
    };
  }
  const Addr: Person["addr"] = {
    city: "city",
    street: "street",
    num: 0,
  };
};

/**
 * 技巧
 *  找到 Object rest 类型
 */
//
before => {
  interface XYZ {
    x: number;
    y: number;
    z: number;
  }
  const restObj: XYZ = { x: 1, y: 2, z: 3 };
  const { x, y, z, ...rest } = restObj;
  function dropXYZ(restObj: XYZ, ...rest) {
    return rest;
  }
};
// after (Pick , Exclude)
after => {
  interface XYZ {
    x: number;
    y: number;
    z: number;
  }

  type DropXYZ<T> = Pick<T, Exclude<keyof T, keyof XYZ>>;

  function _dropXYZ<T extends XYZ>(
    restObj: XYZ,
    ...rest: Array<DropXYZ<T>>
  ): Array<DropXYZ<T>> {
    return rest;
  }
};



结束了?

...

还有个小彩蛋~

这里有个关于 Promise 的小题目:


  const p1 = new Promise((resolve,reject) => {
    console.log('Promise 1');
    resolve();
  }).then(() => {
    console.log('then 11');
    const p2 = new Promise((resolve,reject) => {
      console.log('Promise 2');
      resolve();
    }).then(() => {
      console.log('then 21');
    }).then(() => {
      console.log('then 22');
    })
  }).then(() => {
    console.log('then 12')
  })
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容

  • 为了便于后期维护,本人在 Github 上新建了一个 awesome-typescript 项目,欢迎大家分享新的...
    semlinker阅读 6,328评论 0 65
  • 很多时候虽然我们了解了TypeScript相关的基础知识,但是这不足以保证我们在实际项目中可以灵活运用,比如现在绝...
    java成功之路阅读 3,492评论 0 1
  • 歌词/孟文豪 斩情思三千 断不了思念 剪相思红线 却愈发留恋 写情诗三千 换不回红颜 画丹青美眷 却背影渐远 你的...
    馨晴百合阅读 1,140评论 1 10
  • 《等你一起出发》 ——文/飞雪 我慢慢等你长大 不怕岁月将我变老 我等你一起出发 走过山山水水 大手拉着小手 路在...
    洛阳牡丹文化诗社阅读 344评论 0 0
  • Servlet 是什么?Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 We...
    李序锴阅读 210评论 0 1