一文彻底搞懂TS的基础

简介: 系列

TypeScript 学习笔记

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,                   /* Enable incremental compilation */
    "target": "es5",                          /* 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
    "module": "commonjs",                     /* 指定模块代码生成: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    // "lib": [],                             /* Specify library files to be included in the compilation. */
    // "allowJs": true,                       /* Allow javascript files to be compiled. */
    // "checkJs": true,                       /* Report errors in .js files. */
    // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    // "declaration": true,                   /* Generates corresponding '.d.ts' file. */
    // "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
    "sourceMap": true,                     /* 源文件与输出文件的映射关系文件。Generates corresponding '.map' file. */
    // "outFile": "./",                       /* Concatenate and emit output to single file. */
    "outDir": "./build",                        /* 输出的js文件目录。Redirect output structure to the directory. */
    "rootDir": "./src",                       /* ts源文件目录。Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    // "composite": true,                     /* Enable project compilation */
    // "tsBuildInfoFile": "./",               /* Specify file to store incremental compilation information */
    // "removeComments": true,                /* 不输出注释到编译结果. */
    // "noEmit": true,                        /* Do not emit outputs. */
    // "importHelpers": true,                 /* 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,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

    /* 严格的类型检查选项 */
    "strict": true,                           /* 启用所有严格类型检查选项。 打开此选项后,下面这些选项就不需要单独设置*/
    // "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. 为false时允许any不用特意声明。*/
    // "strictNullChecks": true,              /* Enable strict null checks. 为false时允许赋值为null*/
    // "strictFunctionTypes": true,           /* Enable strict checking of function types. */
    // "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
    // "strictPropertyInitialization": true,  /* Enable strict checking of property initialization in classes. */
    // "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */
    // "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */

    /* 附加检查。Additional Checks  */
    // "noUnusedLocals": true,                /* Report errors on unused locals. 报告未使用的本地变量 */
    // "noUnusedParameters": true,            /* Report errors on unused parameters. */
    // "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
    // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */

    /* Module Resolution Options */
    // "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the '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": [],                           /* Type declaration files to be included in compilation. */
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true                   /* Enables 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,        /* Enables experimental support for ES7 decorators. */
    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
  }
}
相关文章
|
Android开发
我用过的笔记 Markdown Wiki 工具
我用过的笔记 Markdown Wiki 工具
|
应用服务中间件 nginx
配置nginx时加上--without-http_rewrite_module这个参数,就不需要安装pcre
不加--without-http_rewrite_module这个参数时就是启动URL重写,所以需要pcre ./configure --with-http_stub_status_module --without-http_rewrite_module --prefix=/usr/local/n...
3109 0
|
前端开发 搜索推荐 安全
如何选择CMS网站管理系统?CMS包含哪些功能?
本文主要介绍了CMS(内容管理系统)的概念,以及其在网站管理中的应用。早期的CMS主要以静态HTML+CSS+JS展示,但是随着互联网的发展,功能越来越丰富,如会员管理、多元素素材上传等。
593 3
|
项目管理
NPDP|产品经理的沟通协调能力:塑造产品成功的核心力量
产品经理的沟通协调能力对于产品的成功和团队的高效运作至关重要。只有具备了强大的沟通和协调能力,产品经理才能更好地履行职责,推动产品的发展和公司的业务创新。
|
存储 前端开发 Java
Element el-upload 文件上传/图片上传/拖拽上传/附带参数/附带请求头部详解
文目录 1. 前言 2. 基本用法 2.1 前端部分 2.2 后端部分 2.3 获取后端返回信息 3. 外观功能介绍 3.1 拖拽上传 3.2 显示图片 3.3 设置文件列表样式 3.4 显示提示信息 4. 事件功能介绍 4.1 限制上传文件数量 4.2 限制上传文件类型和大小 4.3 移除文件处理 4.4 手动上传 5. 附带参数 6. 附带请求头部 7. 小结
7788 0
|
缓存 NoSQL Java
Springboot 多级缓存设计与实现
Springboot 多级缓存设计与实现
|
关系型数据库 MySQL 数据库
MySQL 复制A的表结构和数据到表B
在MySQL中复制表A至表B可通过不同方法实现。一种是先用`CREATE TABLE B LIKE A;`复制结构,再用`INSERT INTO B SELECT * FROM A;`填充数据。另一种更简便的方法是直接使用`CREATE TABLE B AS SELECT * FROM A;`一次性完成结构和数据的复制。还有一种高级方法是通过`SHOW CREATE TABLE A;`获取表A的创建语句,手动调整后创建表B,如有需要再用`INSERT INTO ... SELECT`复制数据。注意权限问题、跨数据库复制时需指定数据库名,以及大表复制时可能影响性能。
1032 1
|
Web App开发 缓存 安全
Chrome浏览器启动参数大全
这是一组用于定制浏览器行为的命令行参数,包括但不限于:不停用过期插件、放行非安全内容、允许应用中心脚本、停用GPU加速视频、禁用桌面通知、禁用拓展及各类API、调整缓存设置、启用打印预览、隐身模式启动、设定语言、使用代理服务器、无头模式运行等。通过这些参数,用户可以根据需求灵活调整浏览器功能与性能。
|
人工智能 测试技术 开发工具
C++中的AI编程助手添加
Fitten Code是一款适用于多种编程环境,如VS Code和Visual Studio的AI编程助手插件。它能自动生成代码、提供实时建议和解决方案,帮助调试错误,支持80多种语言,包括Python、C++等。用户可以通过插件的智能补全功能提高编码速度,使用AI问答解决编程问题,还能生成代码注释、单元测试,检查和修复潜在的代码错误。Fitten Code是免费的,并且提供代码编辑和转换功能,增强开发效率。
571 1
|
缓存 NoSQL 安全
Redis经典问题:缓存击穿
本文探讨了高并发系统中Redis缓存击穿的问题及其解决方案。缓存击穿指大量请求同一未缓存数据,导致数据库压力过大。为解决此问题,可以采取以下策略:1) 热点数据永不过期,启动时加载并定期异步刷新;2) 写操作加互斥锁,保证并发安全并设置查询失败返回默认值;3) 预期热点数据直接加缓存,系统启动时加载并设定合理过期时间;4) 手动操作热点数据上下线,通过界面控制缓存刷新。这些方法能有效增强系统稳定性和响应速度。
1023 0

热门文章

最新文章