# TypeScript 是什么
- TypeScript 是由 Microsoft 开发的一种开源编程语言,它扩展了 JavaScript,增加了静态类型系统和类、接口等面向对象的特性。TypeScript 代码在编译时会被转换为纯 JavaScript 代码,可以在任何支持 JavaScript 的环境中运行。
# 环境安装
- 需要先安装 nodejs
# 全局安装 typescript | |
npm install typescript -g |
# 查询 typescript 版本 | |
tsc -v |
# 初始化 typescript 项目,执行命令后会在根目录下生成 tsconfig.json, 可以通过修改该文件设置编译器的各种规则,比如严格模式 strict 等 | |
tsc --init |
- 创建
ts
文件,比如index.ts
,然后编写测试代码
let str:string='Hello World'; | |
console.log(str); |
- 编译后运行
# 监控目录下所有 ts 文件变化,如果文件内容改变会自动将其编译为 js 文件,ts 文件修改完以后直接执行 js 文件即可 | |
tsc -w | |
# 新建终端执行 js 文件测试效果 | |
node index.js |
- 或者使用
ts-node
插件运行
# 安装 ts-node 插件 | |
npm install ts-node -g | |
# 初始化 npm,执行后会生成 package.json | |
npm init -y | |
# 安装 TypeScript 的 nodejs 声明 | |
npm install @types/node -D | |
# 运行 ts 文件 | |
ts-node index.ts |
# arguments 对象
- arguments 对是一个类数组对象,作用域在方法内部时,包含了当前函数被调用时传入的所有参数,也可以转换为数值,使用 arguments 调试的时候很方便
function foo(...params: any[]) { | |
console.log(arguments); //[Arguments] { '0': 123, '1': 'hello', '2': true } | |
const args = Array.from(arguments); // 将 arguments 对象转换为数组 | |
console.log(args); // [ 123, 'hello', true ] | |
} | |
foo(123, "hello", true); |
# Any 类型和 Unknown 类型
# 相同点
- any 和 unknown 都是顶级类型,是 Object 类型的父类
# 不同点
- unknown 只能赋值给自身或者 any
- unknown 表示不确定类型的参数,不允许调用对象的任何属性和方法,否则会出现编译错误,可以只用于方法中的输入或输出,是安全型的 any
# Never 类型
- 用于从来都不会返回值的函数 (比如死循环),或者无论如何都会抛出异常的函数
const loop = (): never => { | |
while (true) { } | |
} | |
const error = (): never => { | |
throw new Error(); | |
} |
# Object 和 object 类型
- Object(大写)和 Java 和 C# 一样都包含了所有类型,可以存放任意值
- object(小写)只能存放引用类型或者函数
let a1:Object = 123 | |
let a2:Object = true | |
let a3:Object = '123' | |
let a4:Object = {} | |
let a5:Object = [] | |
let a6:Object = ()=>123 | |
let b1:object = 123 // 报错 | |
let b2:object = true // 报错 | |
let b3:object = '123' // 报错 | |
let b4:object = {} | |
let b5:object = [] | |
let b6:object = ()=>123 |
# Interface
# 多个同名的 Interface 会进行合并
interface Person { | |
name: string; | |
} | |
interface Person { | |
age: number; | |
} | |
let p1: Person = { | |
name: "111", | |
age: 18 | |
} |
# 可空类型?和只读类型 readonly
interface Person { | |
name: string; | |
age?: number;// 可空类型 | |
readonly id:number// 只读 | |
readonly print:()=>{}// 只读 | |
} | |
let p1: Person = { | |
name: "111", | |
id:1, | |
print:()=>{return true} | |
} | |
p1.id=2;// 报错 | |
p1.print=()=>{return false}; // 报错 |
# 继承 extends
interface ClassA { | |
name: string; | |
} | |
interface ClassB { | |
age: number; | |
sex: boolean | |
} | |
// 可以继承多个 | |
interface Person extends ClassA, ClassB { | |
print: () => {}; | |
} |
# 接口定义函数
interface Show{ | |
(name:string,age:number):string | |
} | |
const fn:Show=(name:string,age:number)=>`${name}:${age}` | |
console.log(fn('张三',18)); |
# Interface 索引签名
- 实现 Interface 的对象的属性数量必须与接口的属数量保持一致,如果只是用到 Interface 中的一小部分属性可以使用属性签名
interface Person{ | |
name:string, // 只定义需要用到的属性 | |
age:number, // 只定义需要用到的属性 | |
// 这里 propName 是可以任意取的名称,变量的名称是 string 类型,值类型是 any | |
[propName:string]:any // 其他属性定义为 any | |
} | |
let p1:Person={ | |
name:'111', | |
age:18, | |
sex:0 | |
} | |
p1.address='2222'; // 可以动态添加更多的属性值 |
- 也可以分开定义固定属性和动态属性
interface Product { | |
name: string; | |
price: number; | |
stock: { | |
[size: string]: number; | |
}; | |
colors: { | |
[color: string]: boolean; | |
}; | |
} | |
const hoodie: Product = { | |
name: 'Hoodie', | |
price: 50, | |
stock: { | |
'S': 5, | |
'M': 8, | |
'L': 3, | |
}, | |
colors: { | |
'Red': true, | |
'Blue': false, | |
}, | |
}; | |
console.log(hoodie.stock['S']); | |
console.log(hoodie.colors['Red']); |
# 数组定义
// 常用定义 | |
let arr1: number[] = [1, 2, 3, 4]; | |
// 泛型定义 | |
let arr2: Array<number> = [1, 2, 3, 4]; | |
// 对象数组 | |
interface Person { | |
name: string | |
} | |
let arr3: Person[] = [{ name: '111' }]; | |
let arr4: Array<Person> = [{ name: '222' }]; | |
// 二维数组 | |
let arr5:number[][]=[[1],[2],[3]]; | |
let arr6:Array<Array<number>>=[[1],[2],[3]]; | |
// 大杂烩数组 | |
let arr7:any[]=[123,'abc',true]; | |
let arr8:[number,string,boolean,{}]=[123,'abc',true,{name:'333'}] | |
// 剩余参数...args | |
function fn(...args:number[]){ | |
console.log(args); | |
console.log(arguments); | |
} | |
fn(1,2,3,4,5); |
# 函数定义
// 常用定义 | |
function fn1(a: number, b: number): number { | |
return a + b; | |
} | |
// 箭头函数 | |
const fn2 = (a: number, b: number): number => { | |
return a + b; | |
} | |
// 默认参数 | |
const fn3 = (a: number = 1, b: number = 2): number => { | |
return a + b; | |
} | |
// 可选参数 (可空参数) | |
const fn4 = (a: number, b?: number): number => { | |
return a + (b ?? 0); | |
} | |
console.log(fn4(1));// 输出 1 |
# 函数重载
- 函数重载有点复杂,不像 Java 或者 C# 等可以直接写同名的实现方法,还是少用为好
// 函数声明,不写也可以,写了以后 VSCode 可以显示有这些方法可以重载 | |
function message(options: object): void; | |
function message(text: string, onClose?: Function): void; | |
function message(text: string, mode?: string, duration?: number): void; | |
function message(text: string, duration?: number, onClose?: Function): void; | |
// 函数实现 | |
function message( | |
param1: string | object, | |
param2?: number | Function | string, | |
param3?: Function | number | |
): string { | |
if(typeof param1=='string') return param1; | |
if(typeof param1=='object') return param1.toString(); | |
// 以此类推做业务处理... | |
return ''; | |
} | |
// 调用方式 1 | |
message({ | |
mode: "mode", | |
text: "msg", | |
onClose: () => {}, | |
duration: 3000, | |
}); | |
// 调用方式 2 | |
message("msg"); | |
message("msg", () => {}); | |
message("msg", "mode"); | |
message("msg", "mode"); | |
message("msg", "mode", 3000); | |
message("msg", 3000, () => { }); |
# 联合类型 | 和交叉类型 &
// 联合类型,变量可以声明为多个类型 | |
const fn1 = (type: number | string): string => { | |
return type.toString(); | |
} | |
console.log(fn1('666')); | |
// 交叉类型,对象作为参数时可以具有多个类的属性,类似于 extends | |
interface Person { | |
name: string, | |
age: number | |
} | |
interface Man { | |
hobby: string | |
} | |
const fn2 = (man: Person & Man):void => { | |
console.log(man); | |
} | |
fn2({ | |
name:'张三', | |
age:18, | |
hobby:'唱跳rap' | |
}) |
# 断言
const fn = (num: number | string): void => { | |
//const length=num.length;// 报错,类型 “string | number” 上不存在属性 “length”。 | |
console.log((num as string).length);// 告诉编译器传入的 num 一定是 string 类型,编译器不再进行校验 | |
console.log((<string>num).length);// 第二种方式断言 | |
} | |
fn('123456')// 输出 6 | |
fn(123456)// 输出 undefined | |
// |
# ts 编写防抖功能
- 一定时间内连续多次点击只会生效一次
let timer: any; | |
let clickTest = () => { | |
clearTimeout(timer); | |
timer = setTimeout(() => { | |
console.log('clicked'); | |
timer = null; | |
}, 500) | |
} |