安装TypeScript
https://www.tslang.cn/docs/handbook/typescript-in-5-minutes.html
官方文档
TypeScript无法直接在浏览器中运行
Typing强类型,代码编译阶段就能及时发现错误
#需要先安装nodejs
npm install -g typescript
tsc -v
#初始项目
npm init
#lite-server轻量级服务器,-D相当于--save-dev,仅在开发环境有效
npm i -D lite-server
#在package.json中的scripts中加入一行:
"start": "lite-server"
#启动lite-server
npm start
变量声明
var number1 = 1
let number2 = 2
const number3 = 3
function doSomething() {
for (var i = 0; i< 5; i++) {
console.log(i)
}
console.log("finally i = " + i)
}
doSomething()
可以使用node直接执行简单的ts
node main.ts
#复杂的ts文件,需要先编译再执行
tsc main.ts
node main.js
TypeScript的变量类型
boolean string number
array
null undefined
object
tuple(元组)
enum
void
never
any
高级类型
union 组合类型
Nullable 可空类型
Literal 预定义类型
常用变量类型
number:表示数值类型,如 let num: number = 10;
string:表示字符串类型,如 let str: string = "Hello";
boolean:表示布尔类型,如 let flag: boolean = true;
any:表示任意类型,如 let value: any = 5;
void:表示没有返回值的类型,如 function sayHello(): void { console.log("Hello"); }
null 和 undefined:分别表示 null 和 undefined 值
var number1 = 1
let number2 = 2
const number3 = 3
function add (n1: number, n2: number) {
return n1 + n2
}
console.log(number1 + number2)
数组
let list1: number[] = [1,2,3,4]
let list2: Array<number> = [1,2,3,4]
let list3 = [1,2,3,4]
let list4 = [1, "abc"]
let list5: any[] = [1, "abc", true]
元组是一个特殊的数组,固定类型、长度
元组在声明时就要指明类型、长度
let person1: [number, string] = [1, "zhang"]
person1[0] = 10
person1[1] = "wang"
联合类型:可以有多个类型
let union: string | number
union = 2
union = "hello"
let union2: string | number | boolean | string[]
function merge(n1: number | string, n2: number | string) {
if (typeof n1 === 'string' || typeof n2 === 'string') {
return n1.toString() + n2.toString()
} else {
return n1 + n2
}
}
let mergeNumber = merge(1, 2)
let mergeString = merge("hello", "world")
// console.log(mergeNumber, mergeString)
字面量:从指定的几个值里面取一个特定的值
let union3: 0 | 1 | 2
union3 = 2
let literal: 1 | "2" | true | [1,2,3,4]
function merge2(n1: number | string, n2: number | string, resultType: "as-number" | "as-string") {
if (resultType === 'as-string') {
return n1.toString() + n2.toString()
} else if (typeof n1 === 'string' || typeof n2 === 'string') {
return n1.toString() + n2.toString()
} else {
return n1 + n2
}
}
let mergeString2 = merge2("hello", "world", "as-string")
let mergeString3 = merge2(1, 5, "as-number")
console.log(mergeString2, mergeString3)
枚举类型
enum Color {
red,
green,
blue
}
let color = Color.blue
//输出枚举的索引位置
console.log(color)
//指定索引的值
enum Color2 {
red = 5,
green = 10,
blue = 1
}
//索引值可以是字符串
enum Color3 {
red = "red",
green = "green",
blue = 1
}
console.log(Color3.green, Color3.blue)
any:任意类型
let randomValue: any = 666
randomValue = true
randomValue = "abc"
randomValue = {}
//在IDE编译前不会报错,但tsc编译时会提示不是一个function
randomValue()
randomValue.toUpperCase()
unknown
let randomValue1: unknown = 666
randomValue1 = true
randomValue1 = "abc"
randomValue1 = {}
// unknown不保证类型,但保证类型安全
if (typeof randomValue1 === 'function') {
randomValue1()
}
if (typeof randomValue1 === 'string') {
randomValue1.toUpperCase()
}
void:没有返回值
function printResult() {
console.log(234)
}
// 输出undefined,在原生javascript中是没有void的
console.log(printResult())
undefined:没有初化的变量
function printResult2(): undefined {
console.log(123)
// 必须加入return
return
}
console.log(printResult2())
never:一个函数执行不完,如循环体,可以用于处理异常逻辑
function throwError(message: string, errorCode: number) {
throw {
message,
errorCode
}
}
throwError("not found", 404)
function whileLoop(): never {
while(true) {
console.log("123")
}
}
复杂类型
类型适配:Type Assertions
let message: any
message = "abc"
// 上一步指定了string类型的值,但编译器还是认为变量的类型是any
message.endsWith("c")
// 告诉编译器变量的类型:2种语法效果相同
let ddd = (<string>message).endsWith("c")
let ddd2 = (message as string).endsWith("c")
函数类型
let log = function(message) {
console.log(message)
}
let log1 = (message) => {
console.log(message)
}
let log2 = (message: string) => {
console.log(message)
}
let log3 = (message: string, code: number) => {
console.log(message, code)
}
// 可选参数:在参数后面加一个?
let log4 = (message: string, code?: number) => {
console.log(message, code)
}
log4('this is a error')
// 设置默认参数
let log5 = (message: string, code: number = 5) => {
console.log(message, code)
}
log5("test param")
// 注意:可选参数、默认参数只能放在参数的末尾
对象Object
const person = {
firstName: "zhang",
lastName: "san",
age: 18
}
console.log(person.firstName)
Interface接口
interface Point {
x: number
y: number
}
let drawPoint(point: Point) => {
console.log({x: point.x, y: point.y})
}
drawPoint({x: 101, y: 105})
Interface与class
interface IPoint {
x: number
y: number
drawPoint: () => void
getDistances: (p: IPoint) => number
}
class Point implements IPoint {
x: number
y: number
constructor(x: number, y: number) {
this.x = x
this.y = y
}
drawPoint = () => {
console.log({x: this.x, y: this.y})
}
getDistances = (p: IPoint) => {
return Math.pow(p.x - this.x, 2) + Math.pow(p.y - this.y, 2)
}
}
const point = new Point(101, 102)
point.drawPoint()
Access Modifier 访问修饰符
interface IPoint {
x: number
y: number
drawPoint: () => void
getDistances: (p: IPoint) => number
}
class Point implements IPoint {
// 构造函数中使用public,相当于声明一个成员变量,并给变量赋值
constructor(public x: number, public y: number) {
}
drawPoint = () => {
console.log({x: this.x, y: this.y})
}
getDistances = (p: IPoint) => {
return Math.pow(p.x - this.x, 2) + Math.pow(p.y - this.y, 2)
}
}
const point = new Point(101, 102)
point.drawPoint()
封装私有成员变量,setter、getter访问变量
interface IPoint {
getX: () => number
getY: () => number
setX: (value: number) => void
setY: (value: number) => void
drawPoint: () => void
getDistances: (p: IPoint) => number
}
class Point implements IPoint {
// 构造函数中使用public,相当于声明一个成员变量,并给变量赋值
constructor(private x: number, private y: number) {
}
drawPoint = () => {
console.log({x: this.x, y: this.y})
}
getDistances = (p: IPoint) => {
return Math.pow(p.getX() - this.x, 2) + Math.pow(p.getY() - this.y, 2)
}
setX = (value) => {
if (value < 0) {
throw new Error("value不能小于0")
}
this.x = value
}
getX = () => {
return this.x
}
setY = (value) => {
if (value < 0) {
throw new Error("value不能小于0")
}
this.y = value
}
getY = () => {
return this.y
}
}
const point = new Point(101, 102)
point.drawPoint()
Module模块
新建一个文件point.ts
,使用export
导出类
interface IPoint {
getX: () => number
getY: () => number
setX: (value: number) => void
setY: (value: number) => void
drawPoint: () => void
getDistances: (p: IPoint) => number
}
export class Point implements IPoint {
// 构造函数中使用public,相当于声明一个成员变量,并给变量赋值
constructor(private x: number, private y: number) {
}
drawPoint = () => {
console.log({x: this.x, y: this.y})
}
getDistances = (p: IPoint) => {
return Math.pow(p.getX() - this.x, 2) + Math.pow(p.getY() - this.y, 2)
}
setX = (value) => {
if (value < 0) {
throw new Error("value不能小于0")
}
this.x = value
}
getX = () => {
return this.x
}
setY = (value) => {
if (value < 0) {
throw new Error("value不能小于0")
}
this.y = value
}
getY = () => {
return this.y
}
}
在使用之前导入module
// 导入时不需要指定文件后缀
import { Point } from './point'
const point = new Point(101, 102)
point.drawPoint()
泛型
泛型:数据的模板
let list1: number[] = [1, 2, 3, 4]
let list2: Array<number> = [1, 2, 3, 4]
let lastInArray = (arr: Array<number>) => {
return arr[arr.length - 1]
}
const l1 = lastInArray([1, 2, 3])
let makeTuple = <T, Y>(x: T, y: Y) => [x, y]
const v1 = makeTuple(1, "one")
const v2 = makeTuple<boolean, number>(true, 12)
类型别名type
通过给现有类型起一个新的名称,可以方便地引用和复用这个类型
- 基本类型别名
type ID = number;
let userId: ID = 123;
- 联合类型别名
type Result = string | number;
let value: Result = "hello";
- 对象类型别名
type Point = {
x: number;
y: number;
};
let p: Point = { x: 0, y: 0 };
- 函数类型别名
type Greeting = (name: string) => void;
let sayHello: Greeting = (name) => {
console.log(`Hello, ${name}!`);
};
!!表达式
在 JavaScript 中,!!
是一种常见的语法结构,用于将一个值转换为布尔类型
它的作用是将任何数据类型的值转换为对应的布尔值
- 第一个否定运算符
!
:它会将操作数的值转换为布尔类型,并返回相反的结果。 - 第二个否定运算符
!
:它再次将上一步得到的布尔值取反,返回原始操作数的布尔类型。
非布尔类型的转换:
真值(truthy value):除了以下假值以外的所有值都被视为真值。
假值:false、0、NaN、null、undefined、空字符串(‘’ 或 “”)。
console.log(!!null); // false
console.log(!!undefined); // false
console.log(!!0); // false
console.log(!!NaN); // false
console.log(!!''); // false
console.log(!!123); // true
console.log(!!'hello'); // true
console.log(!!{}); // true
console.log(!![]); // true
布尔类型的保持不变:
如果操作数本身已经是布尔类型,!! 不会对其进行任何变换,直接返回该布尔值。
console.log(!!true); // true
console.log(!!false); // false
import type语法
import type 是 TypeScript 中的一种语法,用于导入类型而不导入实际的值。它可以让你在编译时进行类型检查,但不会在运行时引入额外的代码。
普通的 import 语句用于导入具体的值(对象、函数、类等),而 import type 语句用于导入类型声明。
这种语法在使用模块系统(如 ES6 模块或 CommonJS)时特别有用,因为它允许你只引入类型信息,而不会在运行时增加额外的负担或产生副作用。
与普通的 import 不同,import type 后面只能跟类型声明,而不能是具体的值。示例如下:
import type { SomeType } from './someModule';
// 使用 SomeType 声明一个变量
const myVariable: SomeType = {
// ...
};
可选属性 ?(Optional Properties)
可选属性是指在定义对象类型时,某些属性可以存在也可以不存在的特性
通过在属性名后面添加?
,将该属性标记为可选
interface Person {
name: string;
age?: number;
}
当访问可选属性时,需要注意其可能不存在的情况
可以使用安全导航操作符?.
来避免访问不存在的可选属性时出现运行时错误
// 如果 address 属性不存在,安全导航操作符 ?. 会立即返回 undefined,而不会引发错误
console.log(person.address?.city); // 输出:undefined
空值合并运算符 ??(Nullish Coalescing Operator)
空值合并运算符用于从一组可能的值中选择一个非空或定义的值
它提供了一种简洁的方法来处理变量为 null 或 undefined 时的默认值赋予
// 如果 a 不是 null 或 undefined,则返回 a,否则返回 b
a ?? b
const foo = null;
const bar = "Default Value";
const result = foo ?? bar;
console.log(result); // 输出:"Default Value"
与传统的逻辑或运算符||
相比,空值合并运算符??
只会在 a 为 null 或 undefined 时返回 b
而当 a 为其他“假值”(例如 0、false、‘’ 等)时,也会返回 a
const a = 0;
const b = 10;
const result = a ?? b;
console.log(result); // 输出:0
交叉类型 &(Intersection Types)
交叉类型是将多个类型合并为一个新的类型
使用&
可以将多个类型的特性组合到一个类型中,使新类型具备所有类型的属性和方法
假设我们有两个类型 TypeA 和 TypeB:
type TypeA = {
propA: string;
methodA(): void;
};
type TypeB = {
propB: number;
methodB(): void;
};
要创建一个新的类型,该类型包含 TypeA 和 TypeB 的所有特性,可以使用交叉类型:
type CombinedType = TypeA & TypeB;
这样,CombinedType 就会包含 TypeA 和 TypeB 的所有属性和方法:
const obj: CombinedType = {
propA: "Hello",
methodA() {
console.log("Method A");
},
propB: 10,
methodB() {
console.log("Method B");
}
};