本文章基于黑马程序员笔记来编写
目录
TypeScript 的介绍
TypeScript 为什么要为 JS 添加类型支持?
TypeScript 相比 JS 的优势
TypeScript 初体验
安装编译 TS 的工具包
安装命令:npm i -g typescript。
TS的执行过程:
编译并运行 TS 代码
写入:
let str : number = 1245;
console.log(str);
tsc 01.hello.ts
执行完 上面的命令 会在同级目录中会出现一个同名的 JS 文件
node 01.hello.js
执行结果为: 12345
简化运行 TS 的步骤
npm i -g ts-node
使用方式:ts-node hello.ts。
ts-node hello.ts
TypeScript 常用类型
1. 类型注解
let age : number = '20';
// 说明:代码中的 : number 就是类型注解。
// 作用:为变量添加类型约束。比如,上述代码中,约定变量 age 的类型为 number(数值类型)。
// 解释:约定了什么类型,就只能给变量赋值该类型的值,否则,就会报错。
2. 常用基础类型
1. JS 已有类型
原始类型
let MyName : string = '无名氏';
let age : number = 20;
let isLoading :boolean = false;
let a : null = null;
let b : undefined = undefined;
let sy : symbol = Symbol();
对象类型
// 1.数据类型
//写法一:
let num : number[] = [1,2,3,4];
//写法二:
let str : Array<string> = ['a','b','c'];
2. TS 新增类型
例如:数组中既有 number 类型,又有 string 类型,这个数组的类型应该如何写?
联合类型:
// 联合类型:
// 添加小括号,表示:首先是数组,然后,这个数组中能够出现 number 或 string 类型的元素
let arr : (string | number)[] = ['a', 1 ,'b', 2];
let arr1 : number | string[] = ['1','2','3'];
let arr2 : string | number = 123;
类型别名(自定义类型):
type CustomArray = (number | string)[];
let arr3 : CustomArray = [1,'a',2,'b',3];
let arr4 : CustomArray = ['x',1,'y',2];
函数类型:
3. 函数类型
1 单独指定参数、返回值的类型
// ():number 表示 返回值类型为 number类型
// () => number 表示 返回值类型为 number类型
// 方法一
function add(num1 : number , num2 : number) : number{
return num1 + num2 ;
}
// console.log(add(1,2));
// 方法二
const add2 = (num1 : number , num2 : number) : number => {
return num1 * num2 ;
}
// console.log(add2(1,2));
//2. 同时指定参数、返回值的类型。
const add3 : (num1 : number , num2 : number) => number = (num1 , num2) => {
return num1 * num2;
}
console.log(add3(1,2));
//结合联合类型
const add4 : (num1 : number , num2 : string) => (number | string) = (num1 , num2) => {
return num1 + num2;
}
console.log(add4(1,'2')); //number 和 string 相加是连接 12
3.同时指定参数、无返回值的类型
如果函数没有返回值,那么,函数返回值类型为:void。
void类型 是 ts新增的 js中没有的
function greet(name : string) : void {
console.log('Hello' + name);
}
greet("Zys");//HelloZys
使用函数实现某个功能时,参数可以传也可以不传。
这种情况下,在给函数参数指定类型时,就用到可选参数了 可选参数符号 变量名后加 ? 英文问号, 写法为 : xx : ? 。
比如,数组的 slice 方法,可以 slice() 也可以 slice(1) 还可以 slice(1, 3)。
//当第一个是 必选参数, 第二个是 可选参数, 调用函数时第一参数必须传参
function mySlice(start : number, end? : number) : void{
console.log('起始索引' + start, '结束索引' + end);
}
mySlice(1,2);//起始索引 1 结束索引 2
//当第一个是 可选参数, 第二个是 必选参数,
//这时 第二个必选参数 会报错, 因为 必选参数不能位于可选参数后(可选参数后不能添加必选参数)。
function mySlice2(start? : number, end : number) : void{
console.log('起始索引' + start, '结束索引' + end);
}
//mySlice2() 函数报错。
此时的参数 end 会报错提醒 :
对象类型
//对象类型的写法:
let person : { name: string; age: number; sayHi(): void; greet(name: string): void} = {
name : 'java老师',
age : 20,
sayHi() {},
greet(name) {}
}
console.log(person.name);//java老师
let person2 : {
//没在同一行中书写 可以省略分号 ;
name: string
age: number
//sayHi(): void
//利用箭头函数书写
sayHi : () => void
greet(name: string): void
} = {
name : 'web老师',
age : 21,
sayHi() {},
greet(name) {}
}
console.log(person2.age); //21
function myAxios(config: { url: string; method?: string}){
console.log(config); //{ url: 'https:xxx' }
}
//调用 myAxios 函数
myAxios({
url : 'https:xxx',
//method 是可选属性
})
接口
//接口书写:
interface IPerson {
name : string;
age : number;
sayHi() : void;
//可选类型
mmm ?: number
}
//复用 IPerson
let person3 : IPerson = {
name : 'c#老师',
age : 22,
sayHi() {}
}
let person4 : IPerson = {
name : 'python老师',
age : 23,
sayHi() {},
mmm : 12345
}
//interface(接口)书写 interface xxx {}
interface IPerson2 {
name : string;
age : number;
sayHi() : void;
//可选类型
mmm ?: number
}
//使用接口
let person5 : IPerson2 = {
name : 'IPerson2',
age : 22,
sayHi() {}
}
//type (类型别名)
//type (类型别名) 书写 type xxx = {}
type IPerson3 = {
name: string
age: number
sayHi() : void
}
//使用type
let person6 : IPerson3 = {
name : 'IPerson3',
age : 22,
sayHi() {}
}
继承
如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承来实现复用。
比如,这两个接口都有 x、y 两个属性,重复写两次,可以,但很繁琐。
interface Point2D { x: number; y: number }
interface Point3D { x: number; y: number; z : number}
//使用 继承 来复用
interface Point2D { x: number; y: number }
interface Point3D extends Point2D{
// x y 都继承与 Point2D
//Point3D 自己的属性
z : number
}
//调用 Point3D
let p1 : Point3D = {
x : 1,
y : 2,
z : 3
}
console.log(p1.x + p1.y + p1.z); // 相加=6
元组
let position2 : [number,number] = [ 10.2321, 25.1534 ]
//两个number元素 两个元素 0索引 1索引...
let position3 : [number,string] = [ 10.2321, '25.1534' ]
//一个number类型和一个string类型 两个元素 0索引 1索引...
// 扩展:什么时候用 元组呢?
// 确切地知道包含多少个元素,以及特定索引对应的类型。
// 写法 在 [] 中直接指定类型,多个用 逗号分开
类型推论
//1 声明变量并初始化时
let age = 19;
//2 决定函数返回值时。
function fun( num1 : number, num2 : number) {
return num1 + num2;
}
类型断言
<body>
<!-- 写入a标签 -->
<a href="https://www.baidu.com/" id="link">百度</a>
<script>
//获取id元素
const aLink = document.getElementById('link');
</script>
</body>
//aLink 类型为: HTMLElement
// id 类型存在
aLink?.id
//类型“HTMLElement”上不存在属性“href”。
//aLink.href
/使用类型断言:
const aLink2 = document.getElementById('link') as HTMLAnchorElement;
// id 类型存在
aLink2.id
//aLink2 类型为:HTMLAnchorElement
aLink2.href
//aLink2 类型为: HTMLAnchorElement
//这种写法在react中与js语法冲突
const aLink3 = <HTMLAnchorElement>document.getElementById('link');
字面量类型
let str1 = 'Hello TS'
const str2 = 'Hello TS'
function changeDirection(direction: 'up' | 'down' | 'left' | 'right'){
console.log(direction)
}
//此时如果调用 changeDirection 方法, 只能选择四个值
changeDirection('right');
vscode会告诉我们 ,方法 changeDirection的可选值列表。
枚举
// 写法: 枚举的关键字 enum 名字 { 可选值 } 如果有多个可选值 使用 逗号 分开
enum Direction { Up, Down, Left, Right}
function changeDirection(direction: Direction){
console.log(direction)
}
注意:形参 direction 的类型为枚举 Direction,那么,实参的值就应该是枚举 Direction 成员的任意一个。
访问枚举成员:
changeDirection(Direction.Up); //0 枚举的索引位
解释:类似于 JS 中的对象,直接通过点(.)语法访问枚举的成员。
枚举成员的值为数字的枚举,称为:数字枚举。
问题:我们把枚举成员作为了函数的实参,它的值是什么呢?
// 解释:通过将鼠标移入 Direction.Up,可以看到枚举成员 Up 的值为 0。
// 注意:枚举成员是有值的,默认为:从 0 开始自增的数值。
// 当然,也可以给枚举中的成员初始化值。
//比如:
//自定义索引位
enum Direction2 { Up = 10, Down = 20, Left = 1, Right = 39 }
//打印 Up 索引位为: 10
console.log(Direction2.Up); //10
4. 字符串枚举
字符串枚举:枚举成员的值是字符串。
enum Direction3 {
Up = 'Up',
Down = 'Down',
Left = 'Left',
Right = 'Right'
}
TS
enum Direction {
up = 'UP',
down = 'DOWN',
left = 'LEFT',
right = 'RIGHT'
}
function changeDirection(Direction: Direction){
console.log(Direction)
}
changeDirection(Direction.up);//UP
console.log(Direction) //{ up: 'UP', down: 'DOWN', left: 'LEFT', right: 'RIGHT' }
JS
var songs = ['枚举', '原理']
var Direction;
(function (Direction) {
Direction['Up'] = 'UP'
Direction['down'] = 'DOWN'
Direction['left'] = 'LEFT'
Direction['right'] = 'RIGHT'
})(Direction || (Direction = {}))
function changeDirection(Direction) {
console.log(Direction)
}
changeDirection(Direction.Up) //UP
console.log(Direction) //{ Up: 'UP', down: 'DOWN', left: 'LEFT', right: 'RIGHT' }
any 类型
//声明对象 obj
let obj: any = { x: 0 }
obj.bar = 100;
console.log(obj) //打印:{ x: 0, bar: 100 }
console.log(obj.bar) //在any类型下不报错 打印:100
console.log(obj.x) // 确实有这个属性 打印:0
const num : number = obj;
console.log(num); //在any类型下不报错 打印: { x: 0, bar: 100 }
typeof 类型
console.log(typeof 'hello Ts') //string
//定义 变量p 方法
let p = {x: 1, y: '2'} //如果这里写的越复杂推荐使用typeof
//方法一:
function formatPoint(point : {x :number; y: string}){}
//调用方法,把变量p传给函数formatPoint
formatPoint({x : 1, y : '字符串1'})
//方法二: 简写
function formatPoint2(point: typeof p){}
formatPoint2( {x : 2, y : '字符串2'})
//变量或属性的类型
let res = { x: 123 }
let result: typeof res.x
//此时的 result 的类型是 number
//函数调用的类型
function add(num1 : number, num2 : number){
return num1 + num2
}
let value: typeof add(1,2) //报错
此时typeof 只能用来查询变量或属性的类型。
如果查询函数调用的类型,则会报错。