明天插一段题外话,最近团队新增了一个 HC,面试候选人的过程中,看他简历,履历很牛逼,并且外面写的精通 TypeScript

我想那咱们就问一个很根底的问题吧,你理解 Typscriptextends 关键字吗?它都会在那几个场景下应用?

后果很悲观,即便在我写出了 extends 的应用形式时,这位哥们还没想起怎么用,只能含糊其辞。

我连忙换了一个问题,防止太难堪:你理解 ts 工具类型 ExcludeOmit 的应用吗?及它们两个的区别?

这哥们还是不会~

不出意外的一面就挂了,说这个事的起因是,当初经济上行、市场上是狼多肉少,大家肯定要珍惜面试机会,捕风捉影,平时多积攒、多梳理,战时抓机会、少冷场啊。

好了上面说闲事。

extends 关键字实现继承

如果你有看过 TypeScript 官网文档,起码相熟这两个:

  1. extends 关键字能够实现 interface 类型的扩大,

    • 这个也是 interfacetype 类型别名实现扩大的区别之一,类型别名通过 & 穿插类型来实现类型扩大
  2. extends 关键字可用于 class 的继承

比方定义个 Animal 接口

interface Animal {  name: string}interface Person extends Animal {  level: number}const person: Person = {  name: 'Perter',  level: 1}interface Dog extends Animal {  leg: number}const dog: Dog = {  name: 'BaGong',  leg: 4}

如果应用 class

class Animal {  move() {    console.log("Moving along!");  }} class Person extends Animal {  talk(info: string) {    console.log(info)  }}const person = new Person();// Base class methodperson.move();// Derived class methodperson.talk('hello world')class Dog extends Animal {  woof(times: number) {    for (let i = 0; i < times; i++) {      console.log("woof!");    }  }} const d = new Dog();// Base class methodd.move();// Derived class methodd.woof(3);

这种形式就是在践行 extends 单词的本意 扩大

extends 实现类型束缚

很贴切的列子就是 Typescript 的工具类型 Pick,能够通过从一个 类型中选取一组属性汇合来结构一个新的类型。

接下来让咱们实现下:

type MyPick<T, Keys> = {  [key in Keys]: T[key] // error: Type 'key' cannot be used to index type 'T'.}

如果你间接这么写,ts 编译器必定是要报错的。因为用户传入的属性汇合中很可能在 T 中不存在!

所以咱们须要对属性汇合 Keys 进行束缚,束缚其必须为 T 的属性汇合子集。

type MyPick<T, Keys extends keyof T> = {  [key in Keys]: T[key]}// 应用interface Todo {  title: string;  description: string;  completed: boolean;} type TodoPreview = MyPick<Todo, "title" | "completed">; const todo: TodoPreview = {  title: "Clean room",  completed: false,}; todo; // ok

这是第二种形式,对泛型参数进行束缚。

extends 实现条件类型判断

TypeScript 类型体操根底动作中,有一种动作叫:条件类型,条件类型次要用于去判断两个类型之间的关系。

倡议浏览 类型体操根底动作

比方工具类型 Exclude 的实现,就是基于条件类型:

type MyExclude<T, Key> =  T extends Key ? never : T

能够实现基于联结类型 Key ,排除联结类型 T 中匹配的类型。

type T0 = MyExclude<"a" | "b" | "c", "a">; // type T0 = "b" | "c"type T1 = MyExclude<"a" | "b" | "c", "a" | "b">; // type T1 = "c"

在少数工具类型中,都用到了这个个性,最常见的就是递归类型。递归三要素之一就是要有终止条件,而咱们就能够通过 extends 实现终止条件的判断。

比方

  • 实现一个 DeepReadonly 工具类型,能够做到将对象类型的所有属性转为只读:
type DeepReadonly<T> = keyof T extends never ? T : {  readonly [Key in keyof T]: DeepReadonly<T[Key]> : T[Key]} 
  • 实现一个 TrimLeft ,能够实现移除字符串类型的右边空格:
type Space = ' ' | '\n' | '\t'type TrimLeft<S extends string> = S extends `${Space}${infer R}` ? TrimLeft<R> : Stype trimed = TrimLeft<'  Hello World  '> // expected to be 'Hello World  '
  • 实现一个 KebabCase 类型,能够实现对字符串类型的驼峰转横杠:
type KebabCase<T extends string> = T extends `${infer F}${infer R}` ? R extends Uncapitalize<R> ?  `${Uncapitalize<F>}${KebabCase<R>}`  : `${Uncapitalize<F>}-${KebabCase<R>}`  : T;type FooBarBaz = KebabCase<"FooBarBaz">;const foobarbaz: FooBarBaz = "foo-bar-baz";type DoNothing = KebabCase<"do-nothing">;const doNothing: DoNothing = "do-nothing";

是不是很有意思?

最初

祝贺你,通过短短几分钟,有提高了一丢丢。如果此时你正在找工作的话,欢送分割我,我帮你内推,对于岗位的更多详细信息欢送私信交换。

参考

  • TypeScript:https://www.typescriptlang.org/docs/handbook/2/everyday-types...
  • DeepReadonly: https://github.com/type-challenges/type-challenges/blob/main/questions/00009-medium-deep-readonly/README.md
  • TrimLeft: https://github.com/type-challenges/type-challenges/blob/main/questions/00106-medium-trimleft/README.md
  • KebabCase:https://github.com/type-challenges/type-challenges/blob/main/questions/00612-medium-kebabcase/README.md