您当前的位置:首页 > 网站建设 > javascript
| php | asp | css | H5 | javascript | Mysql | Dreamweaver | Delphi | 网站维护 | 帝国cms | React | 考试系统 | ajax |

你可能不知道的typescript实用小技巧

51自学网 2022-05-02 21:33:24
  javascript

前言

用了很久的 typescript,用了但感觉又没完全用。因为很多 typescript 的特性没有被使用,查看之前写的代码满屏的 any,这样就容易导致很多 bug,也没有发挥出 typescript 真正的“类型”威力。本文总结了一些使用 typescript 的小技巧,以后使用 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();// oksomeClass.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 = 4const 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: TodoPreviewinterface 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 : Ttype 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 的类型,然后再传给 TreeIteminterface 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 | numbertype ElementOf<T> = T extends Array<infer E> ? E : never;type TTuple = [string, number];type ToUnion = ElementOf<TTuple>; // string | number// T1 | T2 -> T1 & T2type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;type Result = UnionToIntersection<T1 | T2>; // T1 & T2

总结

typescript 关于类型限制还是非常强大的,由于文章有限,还有其他类型比如联合类型,交叉类型等读者可自行翻阅资料查看。刚开始接触范型以及其各种组合会感觉不熟练,接下来在项目中会慢慢应用,争取将 bug 降至最低限度。

到此这篇关于typescript实用小技巧的文章就介绍到这了,更多相关typescript实用小技巧内容请搜索wanshiok.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持wanshiok.com!


Vue 详解mixins混入用法大全
JS中数据类型的正确判断方法实例
51自学网,即我要自学网,自学EXCEL、自学PS、自学CAD、自学C语言、自学css3实例,是一个通过网络自主学习工作技能的自学平台,网友喜欢的软件自学网站。
京ICP备13026421号-1