[ TS ] 应该知道的知识点

147 阅读5分钟

1.TS相对于js的优势

js的缺点

  • 语言特点决定了js不适应大型的复杂的项目
  • 弱类型,可以随意改变变量的数据类型
  • 解释型语言,很多错在运行时才能报出来

ts的优点

  • 强大的类型检测系统,提前暴露出问题,减少修改bug的时间
  • 使代码可读性和可维护性更好
  • 引入枚举、接口等开发大型项目js缺少的能力

2.有哪些类型

  • 顶层类型:any、unknown 其他所有类型都可以赋值给这两个类型
  • 低层类型:never 是其他所有类型的子集
  • 基本类型:string、number、boolean、null、undefined、object、数组 ps:数组类型限制有两种写法 Array<number> 、 number[]
  • 其他类型: void、字面量类型、元祖类型、组合类型

void:用来定义一个函数的返回值,表示此函数没有返回值,例如:

function():void {
     console.log(11111)
}

never: 通常用于约束函数的返回值,表示该函数永远不可能结束,例如:

function(msg:string):never {
     throw new Error(msg);
}

function():never {
     while(true){}
}

字面量类型:通过字面量约束类型,例如:

let a:"美丽"
// 下面代码如果要给a赋值,只能赋值 “美丽”

元祖类型: 一个固定长度的数组,且每一项的类型固定

组合类型:多种类型任选其一

let a:string|number
// a赋值只能赋值string或者number类型数值

3.函数相关的约束

函数重载 :在函数实现之前,对函数调用的多种情况进行声明

function count(a:string,b:string):string;
function count(a:number,b:number):number;

function count(a: string|number,b: string | number): string | number {
    f (typeof a === "number" && typeof b === "number") {
         return a * b;
     }
     else if (typeof a === "string" && typeof b === "string") {
         return a + b;
     }
     throw new Error("a和b必须是相同的类型");
}

函数可选参数 : 可以在某些参数名后加上问号,表示该参数可以不用传递

4.枚举

枚举的作用: 通常用于约束某个变量的取值范围 字面量加类型别名也能达到同样效果,但是会有问题

字面量类型的问题

  1. 字面量会产生大量重复代码
  2. 字面量会产生实际意义和逻辑意义的混淆,一旦修改,可能涉及代码中很多地方都需要修改
  3. 字面量不会进入到编译结果中

如何定义一个枚举

enum User {
    枚举字段1 = 值1,
    枚举字段2 = 值2,
    ...
}

枚举会以对象的形式出现在编译结果中

枚举的规则

1.枚举的值可以是字符串也可以是数字

2.如果是数字枚举,值会自增

image.png image.png

3.被数字枚举约束的变量,可以直接赋值为数字

4.数字枚举的编译结果 和 字符串枚举有差异

数字枚举

enum Production {
    car,
    airplane,
    steamship,
}
// 编译结果
var Production;
(function (Production) {
    Production[Production["car"] = 0] = "car";
    Production[Production["airplane"] = 1] = "airplane";
    Production[Production["steamship"] = 2] = "steamship";
})(Production || (Production = {}));
//怎么理解这个编译结果
// 可以简单理解为编译结果为一个对象
var Production = {
    "car":0,
    "airplane": 1,
    "steamship": 2,
    0: "car",
    1: "airplane",
    2: "steamship"
}

字符串枚举

enum CarInfo {
    car="Benz",
    color= "black"
}
// 编译结果
var CarInfo;
(function (CarInfo) {
    CarInfo["car"] = "Benz";
    CarInfo["color"] = "black";
})(CarInfo || (CarInfo = {}));
// 可以理解为
var CarInfo = {
    "car":"Benz",
    "color":"black"
}

枚举最佳实践

  1. 最好不要在一个枚举中既有字符串字段也有数字字段
  2. 使用枚举时,尽量使用枚举字段的名称,而不使用真实的值

5.TS的模块化

TS中导入和导出,统一使用es6模块化标准 TS中模块化的编译结果可以通过‘module’配置,配置成es6或是commonjs 编译结果:

如果module配置es6,编译结果没有区别

如果module配置为commonjs,编译结果中导出的声明会变成exports的属性,默认导出会变成exports的default属性

export const name = '加油'

export function sayHello() {
    console.log('你好')
}

export default function() {
    console.log('这是个默认导出')
}

编译后

// 编译结果可以不使用严格模式,因为本身ts已经很严格,配置noImplicitUseStrict 为 true ,
//编译结果中不会使用严格模式
"use strict"; 
Object.defineProperty(exports, "__esModule", { value: true });
exports.sayHello = exports.name = void 0;
exports.name = '加油';
function sayHello() {
    console.log('你好');
}
exports.sayHello = sayHello;
function default_1() { // 默认导出
    console.log('这是个默认导出');
}
exports.default = default_1; // 默认导出

引入文件的编译结果

import myDefault,{ name, sayHello } from "./module";
console.log(name)
sayHello()
myDefault()

编译后

// 主要看后面部分
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
// 主要看后面,不用管上面
const module_1 = __importStar(require("./module"));
console.log(module_1.name);
(0, module_1.sayHello)(); // 相当于 module_1.sayHello()
(0, module_1.default)(); // 相当于 module_1.default()

默认导出报错的解决

有这样一种场景,需要引入fs模块

image.png

这样引入会报错,提示fs模块没有默认导出 我们再看一下编译的结果是什么样,就明白为什么报错了

image.png

如果我们用commonjs去引入fs模块肯定不是这么写对吧

对于这种情况有两种解决方案

方案一

使用这种方式引入

import {readFileSync} from 'fs'

readFileSync('./')

或者

import * as fs from 'fs'

fs.readFileSync('./')

方案二

修改配置文件 esModuleInterop 设置为 true,然后引入还用这种方式

import fs from 'fs'

fs.readFileSync('./')

TS中使用commonjs模块化规范

注意: ts中尽量统一使用es6模块化规范

当然可以完全按照commonjs语法进行书写,但是会丢失类型检查 如果想用commonjs还想保留类型检查,可以这样写

导出

export = {
name: 'jack',
age: 18
}

引入使用import 这样就有类型提示了

image.png

6.接口

接口:inteface

拓展类型:接口、类型别名、枚举、类

TS中的接口: 约束类、对象、函数的契约

接口约束对象

inrefact User {
    name: "Tony",
    age: 18,
    sayHello: ()=> void
}

接口约束函数

inteface sayHello {
    (name: String):void
}

更新中,敬请期待。。。。