TypeScript(一)| 青训营笔记

55 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天

Day04——TypeScript

01——为什么是TypeScript?

动态类型:在执行阶段才会去确定类型的匹配。在浏览器运行一段JavaScript代码,执行过程中,浏览器的JavaScript的解析引擎才会对他进行类型的匹配,假设你写了一个不正确的类型,执行时控制台会报错。

静态类型:是不可以直接执行的,一定是需要先编译,编译完之后才可以执行。

弱类型语言:可以进行类型转换,“1”+1是可以运行的,即隐式类型转换。(而这在强类型语言中是不可以的)

  1. 静态类型
  • 可读性增强:基于语法解析TSDoc,ide增强
  • 可维护性增强:在编译阶段暴露大部分错误

=>多人合作的大型项目中,获得更好的稳定性和开发效率

  1. JS的超集
  • 包含于兼容所有Js特性,支持共存
  • 支持渐进式引入与升级

02——基本语法

基础数据类型

对象类型

// IBytedancer 大写的I开头表示这是一个类型,用于跟普通的对象和类进行区分
const bytedancer: IBytedancer = {
  jobId: 9303245,
  name: 'Lin',
  sex: 'man',
  age:28,
  hobby: 'swimming',
}
// 关键词interface 对IBytedancer进行定义
interface IBytedancer {
  /*readonly 只读属性:约束属性不可在对象初始化外赋值*/
  readonly jobId: number;
  name: string;
  sex: 'man' | 'woman' | 'other';
  age: number;
  /*可选属性:定义该属性可以不存在*/
  hobby?: string;
  /*任意属性:约束所有对象属性都必须是该属性的子类型*/
  [key: string]: any;
}

函数类型

JavaScript 中有两种常见定义函数的方式——函数声明(Function Declaration)和函数表达式(Function Expression)。
一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到。

function add(x, y){
  return x + y;
}
const mult = (x,y) => x * y;


function add(x: number, y: number): number {
  return x + y;
}
const mult: (x: number, y: number) => number = (x, y) => x * y;


interface IMult {
  (x: number, y: number): number;
}
const mult: IMult = (x,y) => x * y;

注意:TypeScript 中的=>用来表示函数定义,左边是输入类型,用括号括起来,右边是输出类型。跟 ES6 中的=>箭头函数还是不同的,不要混淆

可选参数

// 参数 y 可选
function sum(x: number, y?: string): string {
  return x + y
}

默认参数

function sum(x: number, y: string = 'Jane'): string {
  return x + y
}

函数重载

JavaScript本身是个动态语言。 JavaScript里函数根据传入不同的参数而返回不同类型的数据是很常见的。这怎么在类型系统里表示呢?

方法是为同一个函数提供多个函数类型定义来进行函数重载,编译器会根据这个列表去处理函数的调用,重载的函数在调用的时候会进行正确的类型检查。

例一:

function fn(x: number, y: number): number
function fn(x: string, y: string): string
function fn(x: string|number, y: string|number): string|number{
  if(typeof x === 'number' && typeof y === 'number') {
    return x + y
  } else if(typeof x === 'string' && typeof y === 'string') {
    return x + '_' + y
  } else {
    return '错误'
  }
}

// 如果没有前两个重载这里不会报错,输出内容是“错误”
// 如果有了前两个重载这里就会报错,
// 因为此时的参数不符合重载函数的任何一种传参数据类型
fn(10, 'kkk')

例二:

/*对函数getDate进行函数重载*/
function getDate(type: 'string',timestamp?: string): string;
interface IGetDate {
  (type: 'string',timestamp?: string): string,
  (type: 'date',timestamp?: string): Date,
  (type: 'string' | 'date',timestamp?: string): Date | string,
}

/*报错:不能将类型"(type:any,timestamp:any) => string | Date"分配给类型"IGetDate"
        不能将"string | Date" 分配给类型"string"
        不能将"Date"类型分配给类型"string"。 ts(2322)*/
const getDate2:IGetDate = (type,timestamp) => {
  const date = new Date(timestamp);
  return type === 'string' ? date.toLocaleString() : date
}

数组类型

  1. 「类型+方括号」表示

    type IArr1 = number[];

  2. 泛型表示

    type IArr2 = Array<string | number | Record<string,number>>;

  3. 元祖表示

    type IArr3 = [number,number,string,string];

  4. 接口表示

    interface IArr4 { [key: number]: any; }

const arr1: IArr1 = [1,2,3,4];
const arr2: IArr2 = [1,2,'3',{a: 4}];
const arr3: IArr3 = [1,2,'3','4'];
const arr4: IArr4 = ['string',() => null,{},[]];

TypeScript补充类型

/*空类型,表示无赋值*/
type IEmptFunction = () => void;
/*任意类型,是所有类型的子类型*/
type IAnyType = any;
/*枚举类型:支持枚举值到枚举名的正反映射*/
enum EnumExample {
    add = '+',
    mult = '*'
}
EnumExample['add'] === '+'
EnumExample['+'] === 'add'

enum EColor {Mon,Tue,Wed,Thu,Fri,Sat,Sun};
EColor['Mon'] === 0;
EColor[0] === 'Mon'

/*泛型*/
type INumber = Array<number>

泛型

// 泛型函数
// 让函数的参数可以有多种类型,具体什么类型是我们使用的时候决定的
function getRepeatArr(target) {
    return new Array(100).fill(target);
}

type IGetRepeatArr = (target: any) => any[];

/*不预先指定具体的类型,而在使用的时候再指定类型的一种特性*/
type IGetRepeatArrR = <T>(target: T) => T[];

/*泛型接口&多泛型*/
interface IX<T, U>{
    key: T;
    val: U;
}

/*泛型类*/
class IMan<T> {
    instance: T;
}

/*泛型别名*/
type ITypeArr<T> = Array<T>;
/*泛型约束:限制泛型必须符合字符串*/
type IGetRepeatStringArr = <T extends string>(target: T)=> T[];
const getStrArr: IGetRepeatStringArr = target => new Array(100).fill(target);
/*报错:类型"number”的参数不能赋给类型"string"的参数*/
getStrArr(123);

/*泛型参数默认类型*/
type IGetRepeatArr<T = number> = (target: T)=> T[];
const getRepeatArr: IGetRepeatArr = target => new Array(100).fill(target);
/*报错:类型"string"”的参数不能赋给类型"“number"的参数*/
getRepeatArr('123');

类型别名&类型断言

类型别名——type关键字

类型断言——告诉ts编译器:“我知道我在干什么,我能确定我现在的这个变量是什么类型”。ts 会假设你已经进行了类型的检查。

/* 通过type关键字定义了I0bjArr的别名类型*/
type IObjArr = Array<{
    key: string;
    [objKey: string]: any;
}>
function keyBy<T extends IObjArr>(objArr: Array<T>) {
    /*未指定类型时, result类型为{0}*/
    const result = objArr.reduce((res, val, key) => {
        res[key] = val;
        return res;
    }, {});
    /*通过as关键字,断言result类型为正确类型*/
    return result as Record<string, T>;
}

字符串/数字字面量

TypeScript允许指定字符串/数字必须的固定值。

  1. IDomTag必须为html、body、div、span中的其一

    type IDomTag = 'html' | 'body' | 'div' | 'span ';

  2. IOddNumber必须为1、3、5、7、9中的其一

    type IOddNumber = 1 | 3 | 5 | 7 | 9;