TypeScript学习笔记

出现的主要目的:解决javascript的类型系统不足。

1. 类型系统

类型安全:

强类型 vs. 弱类型

隐式类型转换:强类型不允许,弱类型允许。

语言层面的类型检查。

类型检查:

静态类型:声明时,就确定了,不允许变更。

动态类型:运行时定义,可以动态变更类型。

目前语言分布情况

javascript类型系统特征

动态类型,弱类型-->不靠谱。

脚本语言,没有编译环节。

规模:复制程度-->越来越复杂(没有类型,开发维护越来越吃力)。

弱类型的问题:

  • 运行时,才能发现异常。
  • 约定规定类型,多人开发难以保证。
  • 对象索引器的错误使用。

君子约定存在隐患,强制要求有保障。

强类型的优势:

  • 问题及早暴露。
  • 代码更智能,编码更准确--智能提示(IDE)。
  • 重构更加牢靠。
  • 减少不必要的类型判断。

2. Flow-Javascript的类型检查器了解

类型注解:

增加类型注解的方式。

// @flow
function sum(a:number,b:number):number{
    return a+b;
}

a:number类型注解(需要的地方增加);

Flow小工具,so easy!中间加入了编译的小环节。

通过Flow可以检查代码中的类型问题。

运行阶段:移除类型注解。

  • flow-remove-types 方式。
  • @bable/core、@bable/cli、@bable/preset-flow方式。

开发工具插件:

vscode+Flow Language Support:直接再开发工具中显示,保存后提示。

类型推断:

根据代码的使用情况,推断变量类型。

原始类型:

//@flow
//基本类型
let a:string="123";
let b:number=NaN;//包含NaN,Infinity
let c:boolean=true;
let d:null=null;
let e:void=undefined;
let f:symbol=Symbol();

//数组
let arr:Array=[1,2];
let arr:number[]=[1,2];

//元组
let arr[string, number]=["test", 100];

//对象
let obj1:{name:string,arge:number}={"name":"shang",age:20};
let obj1:{name?:string,arge:number}={age:20};//?可有可无

let obj1={};
obj1.name="zhangsan";
obj1.age=20;

let obj1:{[string]:string}={};
obj1.name="zhangsan";
obj1.age="20";

//函数类型
function foo(callback:(string,number)=>void){
    callback("test",100);
}

//特殊类型
const a:"foo"="foo";//字面量
const tyep:"red" | "blue"="red";

type stringOrNumber=string|number;
const a:stringOrNumber="test";

//maybe类型(扩展了null和undefined类型)
const a:?number=undefined;

//Mixed类型
//mixed=string|number|...等所有类型

//Any类型
//any=string|number|...等所有类型

//any和mixed区别:any时弱类型不再进行语法检查,mixed时强类型仍然进行强类型检查,逻辑中需要进行typeof进行类型判断。

运行环境API: 内置对象

//这些内置函数的参数约定,来自于Flow自动下载的定义。
let a:HTMLElement=document.getElementById("test");

3. TypeScript-javascript的超集

包含:Javascript、类型系统和ES6+

经过编译:javascript(可以选择版本)。

优点:

  • 任何js运行环境都可以使用typescript。
  • 功能更强大,生态健全、完善(vscode)。
  • 前端领域的第二语言。
  • 渐进式的学习。

缺点:

  • 多了很多概念-学习成本增加
  • 增加开发成本-项目初期(特别小项目的情况)。

3.1. 快速上手

#创建文件夹vscode打开
#初始化工程
npm init

#安装typescript环境
npm install typescript -D

文件扩展名.ts。

编译命令:tsc test.ts;

过程:语法检查->js新特性转换->转换为运行时js代码。

3.2. 配置文件

编译文件/编译工程。

#初始化工程
tsc --init

会生成tsconfig.json配置文件。

配置项:

  • target:转换js目标标准。
  • module:模块化方式。
  • outDir:输出目录。
  • rootDirs:源代码目录。
  • sourceMap:是否开启源代码映射。
  • strict:类型检查严格选项,必须明确指定类型。

3.3. 原始类型

const a: string = "test";
const b: number = 100; //NaN Infinity
const c: boolean = true;
const e: void = undefined;
const f: null = null;
const g: undefined = undefined;

//注:严格模式时,变量不可以为null和undefined,非严格模式可以。
//const d: boolean = null;

//配置文件:
//"target": "es5",
//"lib": ["ES2015","DOM"]
//标准库:就是内置对象对应的声明,如果引用不到就会报错。
const h: symbol = Symbol();

中文错误消息的设置:(日常使用中,不推荐)

编译过程:tsc --locale zh-CNvscode:设置中搜索typescript.local,然后设置zh-CN

作用域问题:

自执行函数,包装的方式。

export {}导出方式。推荐的方式

3.4. Object类型

//函数
const a: object = function () {};

//必须完全一致
const b: { name: string; age: number } = { name: "张三", age: 20 };

//限制对象类型应该使用interface方式。

3.5. 数组类型

//数组类型
const arr1: Array = [1, 2];
const arr2: number[] = [1, 2];

function sum(...args: number[]): number {
  return args.reduce((prev, current) => prev + current, 0);
}

sum(1, 2, 3);

3.6. 元组类型

//元组类型
const tuple: [number, string] = [20, "张三"];
//直接提取
// let age = tuple[0];
// let name = tuple[1];

//数组解构的方式
let [age, name] = tuple;

3.7. 枚举类型

//枚举类型
enum Status {
  No,
  Yes,
}
enum Status1 {
  No = "0",
  Yes = "1",
}
enum Status2 {
  No = 0,
  Yes = 1,
}
let a = Status.Yes;

//枚举类型运行时的入侵,影响编译后的结果。
//双向键值对对象:目的是,可以通过索引器的方式访问枚举的名称。
let yes = Status[0];
//如果不适用这种方式获取名称,建议使用常量枚举
const enum Status3 {
  No,
  Yes,
}
let test = Status3.Yes;

3.8. 函数类型

//函数类型
//函数声明
function func1(a: number, b: number): number {
  return a + b;
}
//可选参数,参数名称后增加?
function func2(a: number, b?: number): string {
  return "你好";
}
//参数默认值
function func3(a: number, b: number = 6): number {
  return a + b;
}
//注:可选参数或者默认值参数必须出现在参数列表的最后。
//任意个参数,使用rest运算符:...
function func4(a: number, b: number, ...args: number[]): number {
  return a + b;
}

//函数表达式:
const func5 = function (a: number, b: number): number {
  return a + b;
};
//箭头函数
const func6 = (a: number, b: number): number => a + b;
//函数接口方式
const func7: (a: number, b: number) => number = function (
  a: number,
  b: number
): number {
  return a + b;
};

3.9. 任意类型

//任意类型any:不进行类型检查,轻易不要使用。
let a: any = 90;
a = "你好";

3.10. 隐式类型推断

//隐式类型推断;
let age = 18;
//改变类型,会报错。
//age="12";

//不进行声明,则为any类型
let test;
test = 10;
test = "abc";

3.11. 类型断言

//类型断言
const nums = [100, 20];
const a = nums.find((i) => i > 0);
//会报错,ts不知道a的类型为number。
//let b = a + a;
//断言:as方式
const b = a as number;
let btest = b + b;
//断言:<>方式:注可能与jsx产生冲突,推荐使用as方式。
const c = a;
let ctest = c + c;

3.12. interface接口

//接口
interface User {
  name: string;
  age: number;
  birth?: string; //可选
  readonly sex: string; //只读
}

function sayHello(user: User): string {
  return user.name;
}

//只用于做类型约束,在实际代码运行中,找不到,也不会用。
//可选成员?
//只读成员:readonly

//动态方式
interface Person {
  [prop: string]: string;
}
const person: Person = {};
//可以自由添加属性成员了
person.name = "zhangsan";

3.13. 类:class

//类:ts增强了类的相关语法

//基本用法
class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  sayHi(wel: string): void {
    console.log(wel + this.name);
  }
}

//访问修饰符
class Person1 {
  private name: string;
  public age: number; //默认public
  protected sex: boolean; //只允许子类访问

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
    this.sex = true;
  }

  sayHi(wel: string): void {
    console.log(wel + this.name);
  }
}

class Man extends Person1 {
  constructor(name: string, age: number) {
    super(name, age);
    this.sex = false; //子类可以访问
  }
}

//构造函数也可以进行访问修饰
class Woman extends Person1 {
  private constructor(name: string, age: number) {
    super(name, age);
    this.sex = true; //子类可以访问
  }
  static init(): Woman {
    //static静态类
    return new Woman("zhangsan", 20);
  }
}
let w = Woman.init();

//只读属性
class Woman01 extends Person1 {
  //只读属性,只可在声明或着构造函数立即声明
  private readonly grade: number;
  constructor(name: string, age: number) {
    super(name, age);
    this.grade = 10;
  }
}

//类与接口
interface Person001 {
  run(speed: number): void;
  eat(food: string): void;
}
class Student001 implements Person001 {
  run(speed: number): void {
    console.log("run");
  }
  eat(food: string): void {
    console.log("eat");
  }
}

//抽象类(可以包含具体实现)
abstract class Student002 implements Person001 {
  private name: string;
  constructor(name: string) {
    this.name = name;
  }
  run(speed: number): void {
    console.log("run");
  }
  eat(food: string): void {
    console.log("eat");
  }
}

class Student003 extends Student002 {
  constructor() {
    super("张三");
  }
}

let st = new Student003();
st.eat("馒头");

3.14. 泛型

// 泛型
function createNumberArray(leg: number, value: number): number[] {
  let arr = Array(leg).fill(value); // 泛型的使用方法
  return arr;
}

//把类型变成参数
function createArray(leg: number, value: T): T[] {
  let arr = Array(leg).fill(value); // 泛型的使用方法
  return arr;
}

3.15. 类型声明

import { camelCase } from "lodash";

// 类型声明
//declare function camelCase(input: string): string;

let a = camelCase("hello");

export {};

由于typescript的社区能力,可以对于一些模块,安装类型声明,而提供各种的提示。

模块一般安装到开发环境--save-dev,例如:npm i @types/lodash --save-dev。

安装的文件一般都为:.d.ts的命名方式:专门用于类型声明。


注:有些模块,已经内部集成了类型声明文件。


进一步学习:TypeScript中文网 · TypeScript——JavaScript的超集

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章