美文网首页
TypeScript记录

TypeScript记录

作者: cs0710 | 来源:发表于2020-04-02 14:47 被阅读0次

使用场景: 大型项目或者多人协作

优点:提高开发效率,提高项目健壮性

TS vs JS

  • 是JS的超集,遵循JS的语法和语义,最终编译为原生JS
  • 跨平台且开源
  • 可以重用JS,并且可以无缝使用JS的流行的库(如需要使用,则要tsconfig.json配置文件中开启allowJs: true)
  • TS提供了类、接口和泛型的概念,更易于开发和维护
  • 前端三大框架均支持TS语言环境

01.Typescript开发构建和调试

// 安装前置依赖包

// 安装ts
npm i typescript -g

// 查看typescript安装的版本, @3.8.3
tsc -v

// 一般解决第三方模块文件声明问题
npm i @types/node -D

// 创建tsconfig.json配置文件
tsc --init

// 编译对应的文件
tsc test.ts

以vscode编辑器为例,这里打开终端--运行任务,选择tsc watch -tsconfig.json,自动监视ts文件的改动并编译为js文件到指定输出目录(修改tsconfig.json, "outDir": "./jsFile"即可),对编译后的js文件使用nodemon xxx.js即可运行编译后文件

如需引入第三方组件,则需要安装第三方组件的TS依赖或者自己别写x.d.ts第三方声明,同时也可以通过@ts-ignore不对其进行TS检查

02.Typescript变量类型

TS类型共13种

  • undefined
  • null空类型
  • string字符串类型
  • number数值类型
  • boolean布尔类型
  • enum枚举类型
  • array数组类型
  • tuple元组类型
  • void空类型
  • any任意类型
  • never
  • object
  • 类型断
字符串
// 1. 字符串
const str: string = 'wangcai';

const intro = `
  你好,
  我是${str}
`;
console.log(intro);
数值和布尔
//2. 数字
const num1: number = 16; // 十进制
const num2: number = 0x10; // 16进制
const num3: number = 0o20; // 8进制
const num4: number = 0b10000; // 2进制
console.log(num1, num2, num3, num4); // 16

// 3. 布尔
const bool: boolean = true;
数组
// 4. 数组(两种方式)
const arr1: number[] = [1, 2]; // 数字类型数组
// 范型数组定义形式
const arr2: Array<string> = ['4', '5']; // 字符串数组
console.log(arr1, arr2);
元组
// 5. turple元组,已知类型、顺序和数量确定的(可以定义多种元素类型,但是要按类型顺序赋值),局限性比较大,不推荐使用,使用场景极少
const tur1: [number, string, boolean] = [1, '2', false];
// 使用对应的元素,会自动推断出该元素类型的方法
console.log(tur1[2].valueOf());
枚举
// 6. 枚举
enum Sex {
  male,
  female,
}
const male: number = Sex.male;
const female:number = Sex.female;
console.log(male, female) // 下标索引
// 手动赋值方式
enum Color {
  red = 2,
  green = 'green',
}
const red: number = Color.red;
const green: string = Color.green;
console.log(red, green); // 2 'green'
any
// 7. any类型, 不声明变量类型,默认是any,常用场景:比如我们只知道一部分数据类型时,可以使用,但是尽量少用
let any1: any;
any1 = 7;
any1 = false;
let any2: any[];
any2 = [1, false, 'xm'];

// 8. void类型(空类型),使用场景:一般用于函数的返回值声明
function void1(): void {
  console.log('void类型');
}
void1();
null 和 undefined
// 9. null和undefined, 所有类型的子类型,可以赋值给任意类型(但是这里实践会报错),使用场景: 对变量是否有值不确定时
// 使用联合判断
const null1: object | null = null;
const undefined1: number | undefined = 12;
console.log(null1, undefined1); // null 12
Never
// 10. never:永远不会有值的类型,是任意类型的子类型,但是它没有自己的子类型。使用场景:抛出异常的函数,很少使用,一般使用void进行处理
function never1(msg: string): never {
  throw new Error(msg);
}
// never1('never实践 ');

function never2(): never {
  while(true) {
    console.log('never2');
  }
}
// never2();
object
// 11. object类型,非原始类型,除string、number、boolean、symbol之外的类型
const obj1: object = { age: 18, name: 'xm' };
const obj2: object = [1, 2];
console.log(obj1, obj2);

function obj3(o: object) {
  console.log(o);
}
obj3({ a: 1 });
obj3([1, 2]);
类型断言
// 12. 类型断言,修改已知的变量类型为自定义的变量类型(没有运行时的影响,只会在编译阶段起作用)

// 方式1
const asset1: any = 'i like, like i';
const asset2: string = (<string>asset1).substring(0, 3);
const asset3: any = 456;
const asset4: string = (<number>asset3).toFixed(4);
console.log(asset2, asset3);

// 方式2
const asset5: any = false;
const asset6: boolean = (asset5 as boolean).valueOf();
console.log(asset6)

03.函数的参数

基本函数参数
// 基本函数参数
function fun2(params: string): void {
  console.log(params);
}
fun2('基本函数参数');
可选参数的函数,必选参数不能放在可选参数后
// 可选参数的函数,必选参数不能放在可选参数后
function fun3(params1: boolean, params2?:number) { // 函数不显式指定返回类型时,默认为void类型
  console.log(params1, params2);
}
fun3(false); // false, undefined
fun3(true, 13); // true, 13
默认参数的函数
// 默认参数的函数
function fun4(params:string[] = ['str']) {
  console.log(params);
}
fun4(); // ['str']
fun4(['test']); // ['test']
剩余参数的函数
// 剩余参数的函数
function fun5(...args: any[]): string {
  return args.reduce((prev, curr) => {
    return prev += (curr + '、');
  }, '');
}
const res: string = fun5('cs', 27, 175, '65kg', false);
console.log(res);

04.接口

作用:在开发中,为类命名和为项目中的代码或者第三方代码库定义规范

接口属性必填
// 1. 定义接口
interface Person {
  name: string,
  job: string,
  age: number,
}

// 规范化变量
const person: Person = {
  name: 'xm',
  age: 18,
  job: 'it',
}

// 规范化函数参数
function outPerson(person: Person) {
  console.log(person.name);
}
outPerson(person);
接口中可选属性
// 2. 接口中可选属性
interface CircleParam {
  color?: string,
  radius?: number,
}

interface CircleRes {
  color: string,
  area: number,
}

function createCircle(circle:CircleParam): CircleRes {
  const defaultCircle = { color: 'red', area: 100 };
  if (circle.color) {
    defaultCircle.color = circle.color;
  }
  if (circle.radius) {
    defaultCircle.area = Math.PI * Math.pow(circle.radius, 2);
  }
  return defaultCircle;
}

const createCircle1 = createCircle({color: 'blue'});
const createCircle2 = createCircle({radius: 12});
const createCircle3 = createCircle({color: 'green', radius: 14});
console.log(createCircle1, createCircle2, createCircle3);
接口只读属性
 // 3. 接口的只读属性
interface FullName {
  readonly firstName: string,
  readonly lastName: string,
}
const fullName: FullName = {
  firstName: 'c',
  lastName: 'xm',
}
fullName.lastName = 'ss'; // warning: read-only
console.log(fullName) // 虽然可以编译痛殴,但是ts已经报了警告

// 只读数组
const colors: ReadonlyArray<number> = [1, 2, 3];
colors.push(5); // 直接警告colors read-only
console.log(colors);
接口的任意定义属性
interface SquareConfig {
  width: number,
  height: number,
  [propName: string]: any, // 自定义属性名称
}

function area(params: SquareConfig): void {
  const areaVal = params.width * params.height;
  console.log(areaVal, params);
}
area({ width: 20, height: 10, desc: '矩形', title: '矩形title' });

05.定义函数类型

// 最简洁方式
interface Func1 {
  (param1: number, param2: number): boolean, // 定义接口函数
}

// 对箭头函数进行接口约束,适用于模块化开发
const func1Test: Func1 = (a, b) => {
  console.log(a > b);
  return a > b;
}

func1Test(4, 1);

06.索引类型

// 可索引类型
interface IndexType {
  [index: number]: string, // 自定义字符串类型的索引数组,适用于模块化开发
}
const indexArr: IndexType = ['xm', '2'];
const indexStr: string = indexArr[0];
console.log(indexStr);

07.类类型

// 类类型
// 接口中声明属性和方法(只会检查类的公共属性和方法, 私有和受保护类型不会检查)
interface ClockInterface {
  currDate: Date,
  setDate(d: Date): void,
}
// 对类通过接口进行规范
class Clock implements ClockInterface {
  currDate: Date; // 声明接口中的属性,方法不用重新声明
  constructor(currDate: Date) {
    this.currDate = currDate;
    console.log(this.currDate);
  }
  setDate(d: Date) {
    console.log(d);
  }
}

const clock = new Clock(new Date());
clock.setDate(new Date());

08.接口继承

接口继承(一个接口的成员复制到另一个接口)

分割重用的思想

// 继承单接口
interface People {
  firstName: string,
}

// 接口继承,并且继承firstName属性
interface Programmer extends People {
  job: string,
}

// 使用断言的方式,定义属性规范
const programmer = {} as Programmer;

programmer.firstName = 'wang';
programmer.job = 'web';
console.log(programmer);

// 继承多接口
interface Male {
  sex: string,
}
// 多接口继承,用','分开
interface Student extends Male, People {
  class: string,
}

const student = {} as Student;
student.firstName = 'li';
student.sex = '男';
student.class = '三年级';
console.log(student);

09.类与继承

class Animal {
  name: string;
  constructor(props: { name: string }) {
    this.name = props.name;
  }
  sayAnimal() {
    console.log('sayAnimal' + this.name);
  }
}

class Cat extends Animal {
  kind: string;
  constructor(props: { name: string, kind: string }) {
    super(props);
    this.kind = props.kind;
  }
  sayCat() {
    console.log(`我是${this.name},属于${this.kind}`);
  }
}

const cat = new Cat({ name: '小黑', kind: '猫' });
cat.sayAnimal();
cat.sayCat();

10.子类重写并在内部调用父类方法

内部通过super调用父类的方法

class Mammal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  move(distance: number = 0) {
    console.log(`${this.name}跑了${distance}m`);
  }
}

class Horse extends Mammal {
  constructor(name: string) {
    super(name);
  }
  move() {  // 重写父类方法
    console.log('开始调用父类的方法');
    // 内部通过super调用父类的方法
    super.move(200);
  }
}

const horse = new Horse('小马');
horse.move();

11.类类型说明与比较

公共类型

公共类型作用域在当前类、当前类实例和其子类以及子类实例中

// 当前类
class People {
  // 不声明默认就是public类型
  name: string;
  public age: number; // 公共类型
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  peopleSay() {
    console.log(this.name, this.age);
  }
}

// 子类
class Man extends People {
  constructor() {
    super('xm', 18);
  }
  manSay() {
    // 公共属性可以访问到
    console.log(this.name, this.age);
  }
}

const people = new People('people', 24);
const man = new Man();
// 公共属性外层实例可以访问到
people.peopleSay();
console.log('people.name', people.name);
man.manSay();
console.log('man.name', man.name);
受保护类型

受保护类型作用域仅在当前类中和其子类中

// 受保护类型
class Car {
  protected price: number;
  constructor(price: number) {
    this.price = price;
  }
  carSay() {
    console.log('car say', this.price);
  }
}

class Auto extends Car {
  constructor() {
    super(2000);
  }
  autoSay() {
    console.log('auto say', this.price);
  }
}

const car = new Car(30000);
car.carSay();
console.log(car.price);
const auto = new Auto();
auto.autoSay();
console.log(auto.price);
私有类型

私有类型作用域仅在当前类中

// 私有类型
class Job {
  private place: string;
  constructor(place: string) {
    this.place = place;
  }
  jobSay() {
    console.log('job place', this.place);
  }
}

class Teacher extends Job {
  constructor() {
    super('学校');
  }
  teacherSay() {
    console.log('teacher place', this.place); //  属性“place”为私有属性,只能在类“Job”中访问。
  }
}

const teacher = new Teacher();
console.log(teacher.place); // 属性“place”为私有属性,只能在类“Job”中访问。// 私有类型
class Job {
  private place: string;
  constructor(place: string) {
    this.place = place;
  }
  jobSay() {
    console.log('job place', this.place);
  }
}

class Teacher extends Job {
  constructor() {
    super('学校');
  }
  teacherSay() {
    console.log('teacher place', this.place); //  属性“place”为私有属性,只能在类“Job”中访问。
  }
}
const job = new Job('工厂');
job.jobSay();
console.log('jon 实例', job.place); // 属性“place”为私有属性,只能在类“Job”中访问。
const teacher = new Teacher();
console.log(teacher.place); // 属性“place”为私有属性,只能在类“Job”中访问。
类修饰符

readonly 只能在声明时或者构造函数中被初始化,作用域为当前类、当前类实例和其子类以及子类实例中都可访问,但不能修改

// readonly 
class DecoratorClass {
  readonly name: string = 'readonly';
  updateProp() {
    this.name = 'update readonly'; // Cannot assign to 'name' because it is a read-only 
  }
}
class SubDecoratorClass extends DecoratorClass {
  constructor() {
    super();
  }
  subUpdateProp() {
    console.log('sub', this.name);
  }
}
const decoratorClass = new DecoratorClass();
console.log(decoratorClass.name);
const subDecoratorClass = new SubDecoratorClass();
subDecoratorClass.subUpdateProp();

12.类的静态属性

静态属性只属于当前类的属性,不属于类实例的属性

// static
class StaticClass {
  static fullName: string = 'xm';
  age: number = 18;
  desc() {
    // 静态属性只能通过StaticClass去访问,不属于实例对象this的属性
    console.log(StaticClass.fullName + '芳龄' + this.age);
  }
}

const staticClass = new StaticClass();
staticClass.desc();

13.抽象类

  • 抽象类是派生类的基类,直观理解:抽象类是父类,派生类是子类。抽象类中也可以定义抽象方法,只需定义签名方法就可以,具体实现可以放在派生类中实现
  • 派生类只能继承抽象方法、公共方法与属性,不能继承基类的抽象属性
  • 抽象类不能进行实例化,一般使用场景很少,只做了解
// 抽象类
abstract class Department {
  go() {
    console.log('开始go');
  }
  abstract say(): void; // 不能有具体实现,必须定义在抽象类中
}

class Hr extends Department {
  
  say() { // 对抽象方法具体实现
    console.log('我是派生类的具体实现');
  }
}

const hr = new Hr();
hr.go();
hr.say();

14.泛型

基础使用

可灵活定义数据类型,用封装的思想将数据类型统一规范化

// 泛型基本使用,对输入输出类型统一化
// 基本格式
function print<T>(param: T): T {
  return param;
}

console.log(print('xm'));
console.log(print(true));
console.log(print(10));

// 泛型基本使用,对输入输出类型统一
function print<T>(param: T[]): T[] {
  console.log(param.length);
  return param;
}

// 使用泛型定义数组,比元组更好用的方式,数组中元素可以是任意类型
console.log(print(['xm', false, 10, [1, 2]]));
强制规范泛型的属性

强制传入的参数中含有某个属性

// 例如传入参数中必须包含length属性
interface LengthProp {
  length: number;
}
class Len<T extends LengthProp> {
  name: T;
  constructor(name: T) {
    console.log(name.length);
    this.name = name;
  }
}

const len1 = new Len('100'); // 3
const len2 = new Len(100); // undefined, error: 数值100不含有length属性
const len3 = new Len({ a: 1, length: 999 }); // 999

// 传入对象中必须包含某个key, 使用keyof关键字进行判断,可作为进阶用法了解
class ObjKey<T, K extends keyof T> {
  constructor(obj: T, key: K) {
    console.log(obj[key]);
  }
}

const objKey1 = new ObjKey({a: 1}, 'a');
const objKey2 = new ObjKey({a: 1}, 'c'); // error: c不是{a: 1}中的属性

15.类型推断(比较简单,不做详细记录)

类型推断默认使用最佳通用规则自动推断,如果我们对类型加上注解之后,就会以我们添加的类型注解进行推断

// 类型自动推断
let hobby = 'ball'; // string
hobby = 10; // 不能将类型“number”分配给类型“string”

const props = ['xm', 10, null, undefined, false]; // (string | number | boolean | null | undefined)[]

相关文章

  • TypeScript 基础

    以下为学习极客时间 《TypeScript 开发实战》的学习记录。 TypeScript 环境配置 安装 ts: ...

  • TypeScript记录

    使用场景: 大型项目或者多人协作优点:提高开发效率,提高项目健壮性TS vs JS是JS的超集,遵循JS的语法和语...

  • typescript+react的两种不同的脚手架搭建过程记录

    typescript日渐成为主流技术,本文记录基于typescript的react脚手架的两种不同的搭建过程:20...

  • TypeScript学习记录

    接口-interface person: Person参数必须符合interface的定义才会被允许。 Publi...

  • typescript学习记录

    敲了一遍记不住,留下来以备后续查询之用index.ts 主要记录了ts的基本信息,后面有index.html in...

  • TypeScript学习记录!

    为什么使用 TypeScript ?(1)优点· 程序更加容易理解· 动态语言的约束· 效率更高· 代码自动补全·...

  • typescript学习记录

    typescript基础 数据类型 null undefined是所有数据类型的子类型 任意值 any 类型推论t...

  • TypeScript入门学习@郝晨光

    前言 现在TypeScript越来越火,咱也赶一下潮流,开始学习一下TypeScript,在学习的同时做笔记记录,...

  • react+typescript+antd随笔(一)

    最近在学习typescript,所以试着用typescript来写react项目,记录一下过程中遇到的一些问题及解...

  • TypeScript实践—关于json等非js文件的导入

    有一个需要使用TypeScript 重构的项目,开始学习并研究TypeScript,并记录在此过程中遇到的一些问题...

网友评论

      本文标题:TypeScript记录

      本文链接:https://www.haomeiwen.com/subject/dasxphtx.html