高防服务器

使用typescript的小技巧有哪些


使用typescript的小技巧有哪些

发布时间:2021-08-26 13:59:09 来源:高防服务器网 阅读:96 作者:小新 栏目:开发技术

小编给大家分享一下使用typescript的小技巧有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

    函数重载

    当希望传 user 参数时,不传 flag,传 para 时,传 flag。就可以这样写:

    interface User {    name: string;    age: number;  }    const user = {    name: 'Jack',    age: 123  };    class SomeClass {      public test(para: User): number;    public test(para: number, flag: boolean): number;      public test(para: User | number, flag?: boolean): number {      // 具体实现      return 1;    }  }    const someClass = new SomeClass();    // ok  someClass.test(user);  someClass.test(123, false);    // Error  // someClass.test(123);   //Argument of type 'number' is not assignable to parameter of type 'User'.  // someClass.test(user, false);  //Argument of type '{ name: string; age: number; }' is not assignable to parameter of type 'number'.

    映射类型

    在了解映射类型之前,需要了解 keyof, never, typeof, in。

    keyof:keyof 取 interface 的键

    interface Point {      x: number;      y: number;  }    // type keys = "x" | "y"  type keys = keyof Point;

    never:永远不存在的值的类型

    官方描述:

    the never type represents the type of values that never occur.

    // 例子:进行编译时的全面的检查  type Foo = string | number;    function controlFlowAnalysisWithNever(foo: Foo) {    if (typeof foo === "string") {      // 这里 foo 被收窄为 string 类型    } else if (typeof foo === "number") {      // 这里 foo 被收窄为 number 类型    } else {      // foo 在这里是 never      const check: never = foo;    }  }

    使用 never 避免出现新增了联合类型没有对应的实现,目的就是写出类型绝对安全的代码。

    typeof:取某个值的 type

    const a: number = 3    // 相当于: const b: number = 4  const b: typeof a = 4

    in:检查一个对象上是否存在一个属性

    interface A {    x: number;  }    interface B {    y: string;  }    function doStuff(q: A | B) {    if ('x' in q) {      // q: A    } else {      // q: B    }  }

    映射类型就是将一个类型映射成另外一个类型,简单理解就是新类型以相同的形式去转换旧类型的每个属性。

    Partial, Readonly, Nullable, Required

    • Partial 将每个属性转换为可选属性

    • Readonly 将每个属性转换为只读属性

    • Nullable 转换为旧类型和null的联合类型

    • Required 将每个属性转换为必选属性

    type Partial<T> = {      [P in keyof T]?: T[P];  }    type Readonly<T> = {      readonly [P in keyof T]: T[P];  }    type Nullable<T> = {     [P in keyof T]: T[P] | null   }    type Required<T> = {    [P in keyof T]-?: T[P]  }    interface Person {      name: string;      age: number;  }    type PersonPartial = Partial<Person>;  type PersonReadonly = Readonly<Person>;  type PersonNullable = Nullable<Person>;    type PersonPartial = {      name?: string | undefined;      age?: number | undefined;  }    type PersonReadonly = {      readonly name: string;      readonly age: number;  }    type PersonNullable = {        name: string | null;        age: number | null;  }    interface Props {    a?: number;    b?: string;  }    const obj: Props = { a: 5 };    const obj2: Required<Props> = { a: 5 };  // Property 'b' is missing in type '{ a: number; }' but required in type 'Required<Props>'.

    Pick, Record

    • Pick 选取一组属性指定新类型

    • Record 创建一组属性指定新类型,常用来声明普通Object对象

    type Pick<T, K extends keyof T> = {    [P in K]: T[P];  }    type Record<K extends keyof any, T> = {    [P in K]: T;  }    interface Todo {    title: string;    description: string;    completed: boolean;  }    type TodoPreview = Pick<Todo, "title" | "completed">;    const todo: TodoPreview = {    title: "Clean room",    completed: false,  };    todo; // = const todo: TodoPreview      interface PageInfo {    title: string;  }    type Page = "home" | "about" | "contact";    const nav: Record<Page, PageInfo> = {    about: { title: "title1" },    contact: { title: "title2" },    home: { title: "title3" },  };    nav.about; // = const nav: Record

    Exclude, Omit

    • Exclude 去除交集,返回剩余的部分

    • Omit 适用于键值对对象的Exclude,去除类型中包含的键值对

    type Exclude<T, U> = T extends U ? never : T  type Omit = Pick<T, Exclude<keyof T, K>>    // 相当于: type A = 'a'  type A = Exclude<'x' | 'a', 'x' | 'y' | 'z'>    interface Todo {    title: string;    description: string;    completed: boolean;  }    type TodoPreview = Omit<Todo, "description">;    const todo: TodoPreview = {    title: "a",    completed: false,  };

    ReturnType

    获取返回值类型,一般为函数

    type ReturnType<T extends (...args: any) => any>    = T extends (...args: any) => infer R ? R : any;    declare function f1(): { a: number; b: string };  type T1 = ReturnType<typeof f1>;  //    type T1 = {  //        a: number;  //        b: string;  //    }

    还有很多映射类型,可查看Utility Types参考。

    类型断言

    类型断言用来明确的告诉 typescript 值的详细类型,合理使用能减少我们的工作量。

    比如一个变量并没有初始值,但是我们知道它的类型信息(它可能是从后端返回)有什么办法既能正确推导类型信息,又能正常运行了?有一种网上的推荐方式是设置初始值,然后使用 typeof 拿到类型(可能会给其他地方用)。也可以使用类型断言可以解决这类问题:

    interface User {       name: string;       age: number;   }    export default class someClass {       private user = {} as User;  }

    枚举

    枚举类型分为数字类型与字符串类型,其中数字类型的枚举可以当标志使用:

    enum AnimalFlags {      None = 0,       HasClaws = 1 << 0,       CanFly = 1 << 1,       HasClawsOrCanFly = HasClaws | CanFly   }    interface Animal {       flags: AnimalFlags;      [key: string]: any;   }    function printAnimalAbilities(animal: Animal) {       var animalFlags = animal.flags;       if (animalFlags & AnimalFlags.HasClaws) {           console.log('animal has claws');       }       if (animalFlags & AnimalFlags.CanFly) {           console.log('animal can fly');       }       if (animalFlags == AnimalFlags.None) {           console.log('nothing');       }   }    var animal = { flags: AnimalFlags.None };   printAnimalAbilities(animal); // nothing   animal.flags |= AnimalFlags.HasClaws;   printAnimalAbilities(animal); // animal has claws   animal.flags &= ~AnimalFlags.HasClaws;   printAnimalAbilities(animal); // nothing   animal.flags |= AnimalFlags.HasClaws | AnimalFlags.CanFly;   printAnimalAbilities(animal); // animal has claws, animal can fly
    • 使用 |= 来添加一个标志;

    • 组合使用 &= 和 ~ 来清理一个标志;

    • | 来合并标志。

    这个或许不常用,在 typescript 关于 types 源码中我们也可以看到类似的代码:

    字符串类型的枚举可以维护常量:

    const enum TODO_STATUS {    TODO = 'TODO',    DONE = 'DONE',    DOING = 'DOING'  }    function todos (status: TODO_STATUS): Todo[];    todos(TODO_STATUS.TODO)

    元组

    表示一个已知元素数量和类型的数组,各元素的类型不必相同。

    let x: [string, number];  x = ['hello', 10];

    在发出不固定多个请求时,可以应用:

    const requestList: any[] = [http.get<A>('http://some.1')]; // 设置为 any[] 类型   if (flag) {       requestList[1] = (http.get<B>('http://some.2'));   }   const [ { data: a }, response ] = await Promise.all(requestList) as [Response<A>, Response<B>?]

    范型

    在定义泛型后,有两种方式使用,一种是传入泛型类型,另一种使用类型推断。

    declare function fn<T>(arg: T): T; // 定义一个泛型函数   const fn1 = fn<string>('hello'); // 第一种方式,传入泛型类型   string const fn2 = fn(1); // 第二种方式,从参数 arg 传入的类型 number,来推断出泛型 T 的类型是 number

    一个扁平数组结构建树形结构例子:

    // 转换前数据   const arr = [   { id: 1, parentId: 0, name: 'test1'},   { id: 2, parentId: 1, name: 'test2'},   { id: 3, parentId: 0, name: 'test3'}   ];   // 转化后   [ { id: 1, parentId: 0, name: 'test1',       childrenList: [ { id: 2, parentId: 1, name: 'test2', childrenList: [] } ] },       { id: 3, parentId: 0, name: 'test3', childrenList: [] }   ]      interface Item {       id: number;       parentId: number;       name: string;   }    // 传入的 options 参数中,得到 childrenKey 的类型,然后再传给 TreeItem    interface Options<T extends string> {       childrenKey: T;   }   type TreeItem<T extends string> = Item & { [key in T]: TreeItem<T>[] | [] };   declare function listToTree<T extends string = 'children'>(list: Item[], options: Options<T>): TreeItem<T>[];   listToTree(arr, { childrenKey: 'childrenList' }).forEach(i => i.childrenList)

    infer

    表示在 extends 条件语句中待推断的类型变量。

    type ParamType<T> = T extends (param: infer P) => any ? P : T;

    这句话的意思是:如果 T 能赋值给 (param: infer P) => any,则结果是 (param: infer P) => any 类型中的参数 P,否则返回为 T。

    interface User {       name: string;       age: number;   }   type Func = (user: User) => void   type Param = ParamType<Func>; // Param = User   type AA = ParamType<string>; // string

    例子:

    // [string, number] -> string | number  type ElementOf<T> = T extends Array<infer E> ? E : never;    type TTuple = [string, number];    type ToUnion = ElementOf<TTuple>; // string | number      // T1 | T2 -> T1 & T2  type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;    type Result = UnionToIntersection<T1 | T2>; // T1 & T2

    以上是“使用typescript的小技巧有哪些”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注高防服务器网行业资讯频道!

    [微信提示:高防服务器能助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。

    [图文来源于网络,不代表本站立场,如有侵权,请联系高防服务器网删除]
    [