TypeScript笔记

最近写的函数库,使用了TS,整理下笔记。

类型注解

function fn(person: string):void{ // 参数类型是字符串,没有返回值
    ///...
}
fn('str') // 如传递参数非字符串,vscode编辑器中或在编译时将给出错误提示

const test:number = 1

有哪些基础类型注解?

// 基础类型
:string
:number
:boolean

:null  // 只能是null值
:undefined // 只能是undefined值

:symbol

// 引用类型
:object // 不常用,多使用接口来给对象进行类型注解

// 其他
:any  // 任意类型
:void  // 空,用于函数的无返回值的注解
:never // 用于标注函数代码永远执行不完(如抛出错误的函数,死循环函数)

什么是类型注解和类型推断、类型断言?

类型注解 是显式的标注类型

类型推断 是编辑器根据值来自动推断出类型 (编辑器中鼠标移到变量会显示类型的提示)。

类型断言 是告诉编译器,“相信我,它就是这个类型”。

// 类型注解就是显式的写出类型
const myNumber: number = 123

// 类型推断是根据值来推断类型 (鼠标移到变量会显示类型(或直接显示值)的提示)
const myString = 'test'

// 类型断言(开发者明确知道是什么类型)
const someValue:any = 'abc'
const strLength:number = (someValue as string).length // 断言someValue是字符串类型

对象的类型

// 对象字面量的类型检查
const xiaojiejie: {
  name: string,
  age: number
} = {
  name: '小红',
  age: 18
}

// 标注:object
const obj:object = {}

// 使用接口
interface Person{
    name: string
    age: number
}
const xjj: Person = {
    name: 'xh',
    age: 18
}

// class类的类型检查
class Parson { }
const xiaobai: Parson = new Parson()

// 函数和返回值的类型检查
const fn: ()=> string = () => '123'

函数的类型注解

// 函数返回值的类型注解 fn(): number {}
function getTotal2(one: number, two: number): number {
  return one + two
}
getTotal2(1,2)


// 无返回值: void
function sayHello(): void {
  console.log("Hello")
}

// 永远执行不完的函数
function setTimer():never {
  throw new Error()
  console.log(123)
}

// 参数是对象时的注解 (也可以用接口)
function add({ one, two }: {one: number, two: number}) {
  return  one + two
}

const total = add({one: 1, two: 2})

数组的类型注解

const numberArr: number[] = [1, 2, 3]
const stringArr: string[] = ['a', 'b']
const undefinedArr: undefined[] = [undefined, undefined]
const arr: (number | string | boolean)[] = [1, 'a', true, false] // 用到联合类型

// 类型别名 type alias
type lady = { name: string, age: number }

const xiaojj: lady[] = [
  {
    name: 'xiaojj',
    age: 90
  },
  {
    name: 'j',
    age: 30
  }
]

// 或用类的方式
class Ady2 {
  name: string;
  age: number;
}

const xiaojj2: Ady2[] = [
  {
    name: 'xiaojj',
    age: 90
  },
  {
    name: 'j',
    age: 30
  }
]

元组

元组,可以理解为:已知元素数量和类型的数组

// 联合类型
const xjj:(string | number)[] = ['a',22,'b'] // 规定整个数组当中可以有string或number

// 元组注解 注意这里的注解只有一个中括号
const xjj1: [string, number, number] = ['a', 22, 33] // 规定了数组每个元素对应位置的类型

// Note: 在开发中元祖的使用在相对少


// CSV的方式定义数据格式; (二维数组时需要多加一个中括号)
const xjj2: [string, number, number][] = [
  ['a', 22, 33],
  ['a', 22, 33]
]

接口

接口,可以理解为对象属性的类型描述。和类型别名类似,不同的是 接口必须是一个对象,而别名可以直接是一个类型,如 type Girl = string

interface Girl { // 接口 (理解:对象属性的类型描述)
  readonly name: string; // 只读属性 (定义之后不能再修改)
  age: number;
  waistline?: number; // 加个问号表示是可选值
  [propname: string]: any; // 表示可以有不限制属性名的属性,但属性名需要是字符串,值可以是任意类型
  say(): string; // 函数类型,返回值是string (如无返回值时是 void)。  say()也可以加入参数类型检查,如say(p:number)
}
// 和类型别名类似,不同的是 接口必须是一个对象,而别名可以直接是一个类型,如 type Girl = string

// 接口的继承
interface Teacher extends Girl {
  teach(): string;
}


const girl = {
  name: '大脚',
  age: 18,
  sex: '女',
  say() {
    return '欢迎光临'
  },
  teach() {
    return '教'
  }
}


const screenResume = ({ name, age, bust, sex }: Girl) => {
  console.log(name, age, bust, sex)
}
const getResume = ({ name, age, bust, teach}: Teacher) => {
  teach();
  console.log(name, age, bust)
}
screenResume(girl)
getResume(girl)


// 接口在class类中的使用
class xiaojjj implements Girl {
  name = "xiaojj"
  age = 18
  bust = 98
  sex = '女'
  say() {
    return '欢迎光临'
  }
}

可索引的类型

interface Arr {
    [index: number]:string   // 表示通过索引访问数据时返回的类型是string
}

const myArr:Arr = ['1','2','3']
const myStr:string = myArr[1]

ES6 class类中应用TS

class类的修饰器

// 类的修饰器:
// public (公共) 允许内外部使用
// protected (受保护的) 允许在内部和继承内使用
// private (私有) 允许在内部使用,但不能在继承中使用

// 类的内部和外部,{}内属于内部,外面是外部
class Person {
   // public 内外都可以使用,可省略,不写时默认public。 protected只允许内部使用
  name: string // 这里的string注释是TS使用的
  private age: 18
  public sayHello() {
    console.log(this.name + this.age + 'say hello')
  }
}

class Teacher2 extends Person {
  public sayBye() {
    console.log(this.name + ' say bye') // protected 可以在继承中使用到
  }
}

const person = new Person();
person.name = 'test' // 在类的外部定义
console.log(person.name)

class类的构造函数中使用类型校验

class Person2 {
  constructor(public name: string) {
    this.name = name
  }
}

class Teacher3 extends Person2{
  constructor(public age: number) {
    super('test-name') // 这里传的值是给Person2的构造函数。即使父类没有构造函数,子类的构造函数内也要写super()
  }
}
const teacher3 = new Teacher3(18)
console.log(teacher3.name)
console.log(teacher3.age)

class类的getter、setter和static

class Xjj {
  constructor(private _age: number) { }
  get age() {
    return this._age - 10;
  }  // 访问器属性,以属性的形式访问age,并可以对属性进行包装
  set age(age: number) {
    this._age = age+3;
   }
}

const dj = new Xjj(28);
dj.age = 25

console.log(dj.age)


// 静态属性 static。  静态属性指不需要通过实例化,直接通过Girl.prop的方式就可以访问到属性
class Girl {
  static sayLove() {
    return 'I love you'
  }
}

// const girl = new Girl()
console.log(Girl.sayLove())

class类的只读属性

// 只读属性
class Person {
  public readonly _name: string // 只读属性
  constructor(name: string) {
    this._name = name;
  }
}

const person = new Person('testName');
// person._name = '222'; // 不能修改只读属性
console.log(person._name)

抽象类

/ 抽象类
abstract class Girls {
  abstract skill(); // 注意这里只是定义抽象方法,而不具有方法的实现
}

class Waiter extends Girls{ // 继承了抽象类之后要 实现抽象类内的成员
  skill() {
    console.log('大爷1')
  }
}

class BaseTeacher extends Girls{
  skill() {
    console.log('大爷2')
  }
}

class SeniorTeacher extends Girls{
  skill() {
    console.log('大爷3')
  }
}

联合类型和类型保护

联合类型 指某个参数可以是多种类型。

类型保护 指参数属于某个类型才有相应的操作。

interface Waiter {
  anjiao: boolean
  say: () => {}
}

interface Teacher {
  anjiao: boolean
  skill: () => {}
}

function judgeWho(animal: (Waiter | Teacher)) { // 联合类型
  // 第一种断言方法
  if (animal.anjiao) {
    // (animal as Teacher) 的意思是:断言 animal 是 Teacher类型
    (animal as Teacher).skill()
  } else {
    (animal as Waiter).say()
  }

  // 第二种断言方法
  if ('skill' in animal) {
    animal.skill()
  } else {
    animal.say()
  }

  // 第三种类型保护方法是使用typeof来判断 (代码省略)
}


class NumberObj {
  count: number
}
function addObj(first: object | NumberObj, second: object | NumberObj) { // 联合类型
  if (first instanceof NumberObj && second instanceof NumberObj) { // 类型保护
    return first.count + second.count;
  }
  return 0;
}

枚举

// Enum枚举类型   (个人理解枚举:约定一组可选的常量。 使用常量名表示某个值的含义,增强可读性。)

// js写法
// const Status = {
//   MASSAGE: 0,
//   SPA: 1,
//   DABAOJIAN: 2
// }

// ts写法
enum Status {
  MASSAGE,  // 如果想从1开始,给MASSAGE = 1, 即可
  SPA,
  DABAOJIAN
} // 默认赋值 0 、1、2

console.log(Status.MASSAGE, Status[0]) // 0, MASSAGE  可以通过下标反查

function getStatus(status: any) {
  if (status === Status.MASSAGE) {
    return 'massage'
  } else if (status === Status.SPA) {
    return 'spa'
  } else if (status === Status.DABAOJIAN) {
    return 'dabaojian'
  }
}

const result = getStatus(Status.SPA)
console.log(result)

泛型

泛型,最简单的理解:泛指的类型。(类似函数中的形参与实参)

函数中的泛型使用


// function join(first: string | number, second: string | number) {
//   return `${first}${second}`
// }
// join('jspang', 1); // 如果我想第一个参数是字符串,第二个也必须是字符串,这么就用到泛型


// 泛型使用,如同定义形参,在调用时指定类型
function join<JSPang>(first: JSPang, second: JSPang) {
  return `${first}${second}`
}

join<string>('jspang', '123');
join<number>(11, 22);

// 泛型中数组的使用
function myFun<ANY>(params:ANY[]) { // ANY[] or Array<ANY>
  return params
}
myFun<string>(['a', 'b'])


// 两个类型参数的使用(工作中,常用T表示泛型)
function join2<T,P>(first: T, second: P) {
  return `${first}${second}`
}

join2<string,number>('jspang', 123);
join2<number, string>(11, '22');
join2(11, '22'); // 泛型也支持类型推断 (鼠标移到函数名有提示)

class类中使用泛型

// class SelectGirl {
//   constructor(private girls: string[] | number[]) { } // private 私有的参数,外部无法修改
//   getGirl(index: number): string | number {
//     return this.girls[index]
//   }
// }

// 使用泛型
class SelectGirl<T> {   // 泛型的约束: <T extends number | string>
  constructor(private girls: T[]) { } // private 私有的参数,外部无法修改
  getGirl(index: number): T {
    return this.girls[index]
  }
}

// const selectGirl = new SelectGirl<string>(['大脚', 'xiaohong', 'xiaobai'])
const selectGirl = new SelectGirl<number>([101, 102, 103])
console.log(selectGirl.getGirl(1))


// 泛型中的继承
interface Girl {
  name: string
}
class SelectGirl2<T extends Girl> { // 泛型T中必须有一个name属性,继承自Girl接口
  constructor(private girls: T[]) { } // private 私有的参数,外部无法修改
  getGirl(index: number): string {
    return this.girls[index].name
  }
}

const selectGirl2 = new SelectGirl2([
  {name: '大脚1'},
  {name: '大脚2'},
  {name: '大脚3'}
])

console.log(selectGirl2.getGirl(1))

配置文件tsconfig.json

// 此文件由命令 tsc -init 生成
// 直接运行 tsc 命令就会运用此配置文件
// 选项详解:https://www.tslang.cn/docs/handbook/compiler-options.html
{
  // "include": ["demo15-1.ts"],              // 要编译的指定文件,不配置此项时运行tsc默认编译全部
  // "files": ["demo15-1.ts"],                // 和include类似
  // "exclude": ["demo15-3.ts"],              // 要排除编译的指定文件
  "compilerOptions": { // 编译选项
    /* 基本选项 */
    // "incremental": true,                   /* 启用增量编译 */
    "target": "es5",                          /* 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
    "module": "commonjs",                     /* 指定模块代码生成: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    // "lib": [],                             /* 指定要包含在编译中的库文件. */
    // "allowJs": true,                       /* 允许编译javascript文件*/
    // "checkJs": true,                       /* 报告.js文件中的错误。 */
    // "jsx": "preserve",                     /* 指定 JSX代码生成: 'preserve', 'react-native', or 'react'. */
    // "declaration": true,                   /* 生成相应的 .d.ts文件 */
    // "declarationMap": true,                /* 为每个相应的 .d.ts文件生成一个sourcemap (编译后代码对源码的映射)*/
    "sourceMap": true,                        /* 生成源文件与输出文件的映射关系文件(.map)。*/
    // "outFile": "./",                       /* 将输出文件合并为一个文件. */
    "outDir": "./build",                      /* 输出的js文件目录。 */
    "rootDir": "./src",                       /* ts源文件目录。 */
    // "composite": true,                     /* 启用 项目编译 */
    // "tsBuildInfoFile": "./",               /* 指定用于存储增量编译信息的文件 */
    // "removeComments": true,                /* 不输出注释到编译结果.(删除所有注释,除了以 /!*开头的版权信息。) */
    // "noEmit": true,                        /* 不发出输出.Do not emit outputs. */
    // "importHelpers": true,                 /* 从“tslib”导入发出助手. Import emit helpers from 'tslib'. */
    // "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
    // "isolatedModules": true,               /* 将每个文件作为单独的模块(与“ts.transpileModule”类似) */

    /* 严格的类型检查选项 */
    "strict": true,                           /* 启用所有严格类型检查选项。 打开此选项后,下面这些选项就不需要单独设置*/
    // "noImplicitAny": true,                 /* 对隐含的“any”类型的表达式和声明引发错误. (为false时允许any不用特意声明)*/
    // "strictNullChecks": true,              /* 启用严格的null检查. (为false时允许赋值为null)*/
    // "strictFunctionTypes": true,           /* 启用严格检查函数类型. */
    // "strictBindCallApply": true,           /* 启用函数上严格的“bind”、“call”和“apply”方法. */
    // "strictPropertyInitialization": true,  /* 启用 严格检查类中的属性初始化. */
    // "noImplicitThis": true,                /* 在隐含的“any”类型的“this”表达式上引发错误。 */
    // "alwaysStrict": true,                  /* 以严格模式解析并为每个源文件发出“use strict”。 */

    /* 附加检查。Additional Checks  */
    // "noUnusedLocals": true,                /* 若有未使用的局部变量则抛错 */
    // "noUnusedParameters": true,            /* 若有未使用的参数则抛错。 */
    // "noImplicitReturns": true,             /* 不是函数的所有返回路径都有返回值时报错。*/
    // "noFallthroughCasesInSwitch": true,    /* 报告switch语句的fallthrough错误。(即,不允许switch的case语句贯穿) */

    /* 模块解析选项 */
    // "moduleResolution": "node",            /* 决定如何处理模块:'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                       /* 用于解析非绝对模块名称的基础目录。 */
    // "paths": {},                           /* 模块名到基于 baseUrl的路径映射的列表。 */
    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
    // "typeRoots": [],                       /* List of folders to include type definitions from. */
    // "types": [],                           /* 要包含的类型声明文件名列表 */
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true                   /* 启用s emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
    // "allowUmdGlobalAccess": true,          /* Allow accessing UMD globals from modules. */

    /* Source Map Options */
    // "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */
    // "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

    /* Experimental Options */
    // "experimentalDecorators": true,        /* 启用s experimental support for ES7 decorators. */
    // "emitDecoratorMetadata": true,         /* 启用s experimental support for emitting type metadata for decorators. */
  }
}

随机文章

仅有一条评论

  1. 回复

    那么问题来了,如何学习TypeScript?

添加新评论