typescript的基本、进阶语法(13)

125 阅读6分钟

1.基础篇

export {}

let test1Arr: string[] = ["12312", "123d"];
// 建议使用下面这种,也方便理解泛型
let test2Arr: Array<string> = ["123", "asdwq"];

// 元组
let tupleType: [string, number] = ["2", 1];

// 枚举 - 无赋值,默认数字型枚举,从零开始,依次递增
enum Score {
  BAD, //0
  NG, //1
  GOOD, //2
  GREAT, //3
  PERFECT, //4
}
// console.log(Score);
// {
//     '0': 'BAD',
//     '1': 'NG',
//     '2': 'GOOD',
//     '3': 'GREAT',
//     '4': 'PERFECT',
//     BAD: 0,
//     NG: 1,
//     GOOD: 2,
//     GREAT: 3,
//     PERFECT: 4
// }

// 字符串类型枚举, 数字型枚举才会具有反向映射
enum Score2 {
  BAD,
  NG = "Ng",
  GOOD = 5, // 5
  GREAT, // 6
  PERFECT = "Perfect",
}
// console.log(Score2);
// {
//     '0': 'BAD',
//     '5': 'GOOD',
//     '6': 'GREAT',
//     BAD: 0,
//     NG: 'Ng',
//     GOOD: 5,
//     GREAT: 6,
//     PERFECT: 'Perfect'
// }

/**
 *  any | unknown | void
 */
// any - 绕过所有类型检查 => 类型检测和编译筛查全部失效
let anyValue: any = "anyValue";
anyValue = false;
anyValue = 123;
let valueString: string = anyValue;

// unknown - 绕过赋值检查 => 禁止更改传递
let unknownValue: unknown;
unknownValue = true;
unknownValue = 123;
unknownValue = "unknownValue";
let value1: unknown = unknownValue; // OK
// let value2: boolean = unknownValue; // NOK
let value3: any = unknownValue; // OK

// void - 声明函数返回值为空
function voidFunction(): void {
  console.log("no return");
  // 可以这样写return,但是没有返回值
  return;
}

// never - 永不返回(返回“从不”的函数不能具有可访问的终结点)
function errorFun(msg: string): never {
  throw new Error(msg);
}
function longlongloop(): never {
  while (true) {
    // ...
  }
}

// {} - 描述了一个没有成员的对象
const prop = {};
// prop.a = "zha"; // ERROE

2.type的使用

export {}

/**
 * interface
 */
interface Class {
  name: string;
  time: number;
}

const jiawa: Class = {
  name: "加瓦",
  time: 1000,
};

// 只读 & 任意
interface Class1 {
  readonly name: string;
  time: number;
  [propName: string]: any;
}

/**
 * 交叉类型 &
 */
interface A {
  name: D;
}
interface B {
  name: E;
}
interface C {
  name: F;
}

interface D {
  d: boolean;
}
interface E {
  e: string;
}
interface F {
  f: number;
}

type ABC = A & B & C;

const abc: ABC = {
  name: {
    d: true,
    e: "string",
    f: 10,
  },
};

// 合并冲突
interface AA {
  c: string;
  d: string;
}
interface BB {
  c: number | string; // 不将其设置成联合类型,下面ab对象的c: "string"会报错
  e: string;
}

type AB = AA & BB;
const ab: AB = {
  c: "string",
  d: "string",
  e: "string",
};

/**
 * 断言 - 类型的中间执行时声明、转换(过程中和编译器的交流)
 */
const anyValue1: any = "ss";
const anyValLen: number = (<string>anyValue1).length;
const anyValLen1: number = (anyValue1 as string).length;

/**
 * 类型守卫 - 保障在语法规定范围做进一步确认业务逻辑
 */
interface Teacher {
  name: string;
  courses: Array<string>;
}
interface Student {
  name: string;
  startTime: Date;
}

type Class12 = Teacher | Student;

// 判断属于哪个类型
function startCourse(cls: Class12) {
  if ("courses" in cls) {
    cls.courses;
  } else {
    cls.startTime;
  }
}

// typeof - 类型分类场景下的身份确认
function startCourse1(name: Class12, score: string | number) {
  if (typeof score === "string") {
    score;
  } else {
    score;
  }
}

/**
 * 泛型
 */
function startClass<T, U>(name: T, score: U): string {
  return `${name} + score`;
}
function startClass2<T, U>(name: T, score?: U): T {
  return (name + String(score)) as T;
}

3.装饰器(感觉还是没学到这块的精髓使用)

想用装饰器需要在tsconfig.json里改配置

"experimentalDecorators": true
/**
 * 类装饰器
 */
function decoratorForPerson(target: any) {
  target.age = 18;
}

@decoratorForPerson
class Person1 {
  static age: number;
}

console.log(Person1);
// [class Person1] { age: 18 }

/**
 * 装饰器组合 - 顺序
 */
function demo1(target: any) {
  console.log("demo1");
}
function demo2() {
  console.log("demo2");
  return (target: any) => {
    console.log("demo2里面");
  };
}
function demo3() {
  console.log("demo3");
  return (target: any) => {
    console.log("demo3里面");
  };
}
function demo4(target: any) {
  console.log("demo4");
}

@demo1
@demo2()
@demo3()
@demo4
class Person11 {}
/**
demo2
demo3
demo4
demo3里面
demo2里面
demo1
 */

/**
 * 属性装饰器
 */
function fn3(arg: any) {
  return (target: any, attr: any) => {
    target[attr] = arg;
  };
}
class Obj {
  @fn3(100)
  static age: number;
}

console.log(Obj);
// [class Obj] { age: 100 }

/**
 * 方法装饰器
 */

function fn4(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  console.log("@", target);
  console.log("@@", propertyKey);
  console.log("@@@", descriptor);
}

class Person22 {
  @fn4
  say() {
    console.log("say");
  }
}
const person22 = new Person22();
person22.say();
/**
@ {}
@@ say
@@@ {
  value: [Function: say],
  writable: true,
  enumerable: false,
  configurable: true
}
say
 */

4.TypeScript 中的内置类型

/**
 * 内置类型
 */

/**
 * Partial - 将类型 T 的所有属性标记为可选属性
 */
/**
 * 实现方式
type Partial<T> = {
  [P in keyof T]?: T[P];
};
 */

// 用法:Partial<T>
interface Person4 {
  name: string;
  gender: 0 | 1;
}
const person4: Array<Person4> = [];
// 当我们不需要用到所有属性时
const person4Obj: Partial<Person4> = {
  name: "张三",
};

/**
 * Required - 将类型 T 的所有属性标记为必选属性
 */
//  实现方式
// type Required<T> = {
//   [P in keyof T]-?: T[P];
// };
// -?代表移除?

/**
 * Readonly - 将所有属性标记为 readonly, 即不能修改
 */
//  实现方式
// type Readonly<T> = {
//   readonly [P in keyof T]: T[P];
// };

/**
 * Pick - 从某个类型中过滤出某个或某些属性
 */
// 实现方式
// type Pick<T, K extends keyof T> = {
//   [P in K]: T[P];
// };
interface PickTest {
  name: string;
  age: number;
  sex: 0 | 1;
}
type PickTestP = Pick<PickTest, "name" | "age">;
const pickTest: PickTestP = {
  name: "张三",
  age: 10,
};

/**
 * Record - 标记对象的属性(key)或者属性值(value)的类型
 */
// 实现方式
// type Record<K extends keyof any, T> = {
//   [P in K]: T;
// };
interface Record1 {
  name: string;
  age: number;
}
const recordTest: Record<number, Record1> = {
  1: {
    name: "张三",
    age: 10,
  },
};
const recordTest1: Record<"name" | "id", string> = {
  name: "123",
  id: "sx",
};

/**
 * Exclude - 移除特定类型中的某个(些)属性
 */
// 实现方式
// type Exclude<T, U> = T extends U ? never : T;

type ExcludeTest4 = Exclude<"a" | "b" | "c", "b" | "c">;
// type ExcludeTest4 = "a"

// Exclude 和 Pick 一起用可用来给“对象”重写某些属性,比如下面是去除某些属性
type FilterPick<T, U extends keyof T> = Pick<T, Exclude<keyof T, U>>;
interface Test4 {
  name: string;
  age: number;
  sex: 0 | 1;
}
interface Test44 extends FilterPick<Test4, "name"> {}
const aaa: Test44 = {
  age: 18,
  sex: 0,
};

/**
 * Extract - Exclude 的反操作,取 T,U 两者的交集属性
 */
// 实现方式
// type Extract<T, U> = T extends U ? T : never;
type ExtractTest = Extract<"a" | "b" | "c", "a" | "b">;

/**
 * NonNullable - 排除类型 T 的 null | undefined 属性
 */
// 实现方式
// type NonNullable<T> = T extends null | undefined ? never : T;

/**
 * ReturnType -获取函数类型 T 的返回类型
 */
// type ReturnType<T extends (...args: any) => any> = T extends (
//   ...args: any
// ) => infer R
//   ? R
//   : any;

type MyFunction = (a: number, b: string) => boolean;
// 使用 ReturnType 提取返回值类型
type Result = ReturnType<MyFunction>;
// Result 的类型是 boolean,因为 MyFunction 返回值类型是 boolean

tsconfig配置详解

{
  "compilerOptions": {
    "allowUnreachableCode": true, // 不报告执行不到的代码错误。
    "allowUnusedLabels": false,    // 不报告未使用的标签错误
    "alwaysStrict": false, // 以严格模式解析并为每个源文件生成 "use strict"语句
    "baseUrl": ".", // 工作根目录
    "experimentalDecorators": true, // 启用实验性的ES装饰器
    "jsx": "react", // 在 .tsx文件里支持JSX
    "sourceMap": true, // 是否生成map文件
    "module": "commonjs", // 指定生成哪个模块系统代码
    "noImplicitAny": false, // 是否默认禁用 any
    "removeComments": true, // 是否移除注释
    "types": [ //指定引入的类型声明文件,默认是自动引入所有声明文件,一旦指定该选项,则会禁用自动引入,改为只引入指定的类型声明文件,如果指定空数组[]则不引用任何文件
      "node", // 引入 node 的类型声明
    ],
    "paths": { // 指定模块的路径,和baseUrl有关联,和webpack中resolve.alias配置一样
      "src": [ //指定后可以在文件之直接 import * from 'src';
        "./src"
      ],
    },
    "target": "ESNext", // 编译的目标是什么版本的
    "outDir": "./dist", // 输出目录
    "declaration": true, // 是否自动创建类型声明文件
    "declarationDir": "./lib", // 类型声明文件的输出目录
    "allowJs": true, // 允许编译javascript文件。
    "lib": [ // 编译过程中需要引入的库文件的列表
      "es5",
      "es2015",
      "es2016",
      "es2017",
      "es2018",
      "dom"
    ]
  },
  // 指定一个匹配列表(属于自动指定该路径下的所有ts相关文件)
  "include": [
    "src/**/*"
  ],
  // 指定一个排除列表(include的反向操作)
  "exclude": [
    "demo.ts"
  ],
  // 指定哪些文件使用该配置(属于手动一个个指定文件)
  "files": [
    "demo.ts"
  ]
}

后续需学nest.js去精炼使用ts