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.枚举
枚举的作用: 通常用于约束某个变量的取值范围 字面量加类型别名也能达到同样效果,但是会有问题
字面量类型的问题
- 字面量会产生大量重复代码
- 字面量会产生实际意义和逻辑意义的混淆,一旦修改,可能涉及代码中很多地方都需要修改
- 字面量不会进入到编译结果中
如何定义一个枚举
enum User {
枚举字段1 = 值1,
枚举字段2 = 值2,
...
}
枚举会以对象的形式出现在编译结果中
枚举的规则
1.枚举的值可以是字符串也可以是数字
2.如果是数字枚举,值会自增
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"
}
枚举最佳实践
- 最好不要在一个枚举中既有字符串字段也有数字字段
- 使用枚举时,尽量使用枚举字段的名称,而不使用真实的值
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模块
这样引入会报错,提示fs模块没有默认导出 我们再看一下编译的结果是什么样,就明白为什么报错了
如果我们用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 这样就有类型提示了
6.接口
接口:inteface
拓展类型:接口、类型别名、枚举、类
TS中的接口: 约束类、对象、函数的契约
接口约束对象
inrefact User {
name: "Tony",
age: 18,
sayHello: ()=> void
}
接口约束函数
inteface sayHello {
(name: String):void
}
更新中,敬请期待。。。。