类型系统
强类型 与 弱类型(类型安全角度)
- 强类型:在语言层面限制函数的实参类型必须与形参类型相同
 - 弱类型语言不会限制实参的类型
 - 强类型有更强的类型约束,不允许有任意的隐式类型转换
 - 弱类型中几乎没有什么约束,允许任意的数据隐式类型转换
 - 变量类型允许随时改变的特点不是强弱类型的差异
 
静态类型 与 动态类型(类型检查角度)
- 静态类型:
 
- 一个变量声明时它的类型就是明确的
 - 声明过后,它的类型就不允许再修改
 
- 动态类型:
 
- 运行阶段才能明确变量类型,而且变量类型可以随时发生变化
 - 变量是没有类型的,变量中存放的值是有类型的
 

JavaScript 类型系统特征
- 弱类型且动态
 - 缺失类型系统可靠性
 - 原因:
 - 早前 JavaScript 应用简单
 - JavaScript 没有编译环节,设置成静态类型语言没有意义
 
弱类型产生的问题
- 只有运行阶段才能发现是否有问题
 - 类型不确定造成的函数功能问题,结果和预想的不一样( + )
 - 存在许多的隐式转换
 - 对于小项目可以通过约定来约束,但是开发周期长等的项目会有很大的隐患
 
强类型的优势
- 错误更早暴露
 - 代码更智能,编码更准确
 - 重构更牢靠
 - 减少不必要的类型判断
 
概述
- TypeScript 是 JavaScript 的超集
 - TS 使用更加完善的类型系统和新特性完成开发工作,完成开发工作后会编译成能够在生产环境运行的 JavaScript 代码
 - 任何一种 JavaScript 运行环境都支持
 - 功能比 flow 更为强大,生态更加健全、更完善
 - 属于 渐进式
 

- 缺点:
 - 语言本身多了很多概念
 - 项目初期,会增加一些成本
 
基础使用
- 安装:yarn init --yes、yarn add typescript --dev
 - node_modules/bin/tsc:tsc 命令帮助我们编译 TS 代码(yarn tsc 文件)
 - 配置:yarn tsc --init 初始化配置文件
 
- target:设置编译后的 JavaScript ECMAScript 标准
 - module:输出的代码会采用什么样的方式去模块化
 - outDir:编译结果输出的文件夹 dist
 - rootDir:源代码所在的文件夹 src
 - sourceMap:开启源代码映射
 - strict:严格模式
 - lib:指定所引用的标准库
 - 只有直接编译整个项目才会运行配置文件
 
- 中文错误消息:yarn tsc --locale zh-CN
 
类型
原始类型
- 非严格模式都可以为空
 - 标准库:内置对象所对应的声明
 
// 原始数据类型
// 严格模式不能为空 null
const a: string = "";
const b: number = 0;
const c: boolean = true;
const d: null = null;
const e: undefined = undefined;
// void 只能存放 null/undefined
const f: void = undefined;
// target 改为2015+ 或者改 lib 引用库
const g: symbol = Symbol()Object 类型
- 泛指所有的非原始类型,也就是数组、函数、对象等
 - 如果要具体的对象类型 用字面量的形式
 - 赋值的对象结构必须与定义的结构完全一致
 
数组类型
- 可以使用数组泛型
 - 元素类型[]
 
// 数组泛型
const ary1:Array<number> = [1,2]
// 元素类型[]
const ary2:number[] = [1,2]元组类型
- 明确元素数量
 - 明确元素类型
 - 每个元素不必完全相同
 - 特殊的数组,可以使用下标访问
 
枚举类型
- 可以给一组数值取别名
 - 只会存在一些固定的值,不会出现超出范围的可能性
 - 会入侵到运行时的代码,会生成键值对保存起来,让我们更好的根据值获取名称
 - 如果我们确定我们不会采用索引器的方式去访问名称,那么可以采用常量枚举
 
// 如果不指定值会依次累加  
// 数值枚举:若指定第一个值 会在第一个值的基础之上进行累加
// 字符串枚举:只能自己手动赋值
// 添加 const 关键字 变成常量枚举
const enum Status  {
  ok = 0,
  eror = 1,
}函数类型
- 函数定义方式:函数声明和函数表达式
 - 函数声明:
 
- 参数的注解跟在其后 返回值的注解跟在括号后
 - 参数后面添加 ? 变成可选参数
 - 参数后面添加默认值之后 也会变成可选参数
 - 可选参数必须在必选参数后面
 
- 函数表达式
 
- 可以采用箭头函数的形式
 
function fun1(a:number = 10,b?:number,res:number[]):string {
  return 'fun1'
}
// 函数表达式
const fun2: (a?: number, b?: number | undefined) => string = function(a:number = 10,b?:number):string{
  return 'fun2'
}
const fun3 = function(a:number = 10,b?:number):string{
  return 'fun3'
}任意类型(弱类型)
- 动态类型
 - 不安全,轻易不使用
 
隐式类型推断
- 在没有进行类型约束直接赋值时,会根据赋值类型来推断该类型
 - 推断出来后就相当于添加了 :类型
 - 没有推断出来就会是 any
 
类型断言
- 当我们明确知道类型但是 TypeScript 不一定知道,此时我们可以明确告诉 TypeScript 类型
 - 方式:
<类型>(JSX 下不能使用)、as - 类型断言并不是类型转换(运行时的概念),只是编译过程中的概念,编译过后就不会存在了
 
const nums = [100,200,300]
const res = nums.find( x => x>0)
let age1 = res as number
let age2 = <number>res  // JSX下不能使用作用域问题
- 直接在文件中定义的变量是在全局作用域中的
 - 我们可以使用立即执行函数进行包裹或者采用模块导出(就会成为模块作用域中的局部成员)的方式
 
(function() {const a = 123})()
const a = 123
export {}接口
- 一种规范或者契约,抽象概念
 - 约定对象的结构、约定有哪些成员而且这些成员的类型又是什么样的
 - 使用整个接口就必须遵循接口全部的约定
 - 使用 
interface 关键字 - 
? :可选成员 - 
readonly 修饰成员:只读成员,可以跟在访问修饰符后面 - 
[类型]:类型:动态成员 
interface Student {
  name: string;
  readonly age: number;
    position?:string;
}
function banji(student: Student) {
  console.log(student);
}
// 动态成员 不定数量 不定名称
interface Eat {
  [key:string] : string
}类
- 描述一类事物的抽象特征
 - 用来描述一类具体对象的抽象成员
 - ES6 之前 :函数 + 原型 模拟实现类
 - ES6+:专门的 class
 - TS 增强了 class 的相关语法
 
class Person {
  // 必须声明和初始化
  name:string //= 'zhangsan'  初始化一般在构造函数中进行
  age:number
  constructor(name:string,age:number) {
    this.name = name
    this.age = age
  }
}访问修饰符
- private:私有属性,只能在类中访问
 - public:公有成员,默认
 - protected:也不能在外部访问,只允许在子类中访问,允许继承
 - 如果给了构造函数添加了 private ,那么该类就不能被实例化也不能被继承,就只能在内部添加 静态方法,在静态方法中创建这个类的实例
 
类与接口
- 接口可以对类进行抽象
 - 类后跟 
implements关键去实现接口 - 实现一个接口后就必须包含接口中的全部方法和成员
 
interface EatFood {
  eat (food: string): void;
}
class Animal implements EatFood{
  eat(food:string) {
    console.log("我吃:",food);
  }
}抽象类
- 包含子类当中必须要有的成员,不同于的接口的是可以包含一些具体的实现
 - 比较大的类建议使用抽象类(例如:动物)
 - 只能被继承不能使用 new 的方式创建
 - 类前面使用 
abstract关键字 
// 抽象出类中的公共的一些方法和属性
interface EatFood {
  eat (food: string): void;
}
// ----------抽象类--------
abstract class Animal implements EatFood{
  eat(food:string) {
    console.log("我吃:",food);
  }
  // 抽象方法 没有方法体
  abstract run(speed:number):void
}
class Cat extends Animal{
  // 继承了抽象类就必须实现其方法
  run(speed: number): void {
    console.log('跑的速度:',speed);
  }
}
const cat = new Cat()
cat.run(100)泛型
泛型:指在定义函数、接口、类的时候,不去指定具体的类型,等到在使用的时候再去指定具体的类型
- 为了极大的复用代码
 - 在定义的时候不明确的类型都采用 
T 来代表 - 在调用的时候把类型传递过去
 
function creatArray<T>(length:number,value:T):T[] {
  return Array<T>(length).fill(value)
}
console.log(creatArray<number>(3,100));类型声明
- 一个成员在定义的时候因为种种原因没有进行声明一个明确的类型
 - 我们就可以在使用的时候单独为它进行类型声明
 - 使用 
declare 关键字进行声明 - 由于现在的社区非常完善,我们也可以安装相应的类型声明模块就行了
 










