TypeScript入门笔记

安装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

通过给现有类型起一个新的名称,可以方便地引用和复用这个类型

  1. 基本类型别名
type ID = number;
let userId: ID = 123;
  1. 联合类型别名
type Result = string | number;
let value: Result = "hello";
  1. 对象类型别名
type Point = {
  x: number;
  y: number;
};
let p: Point = { x: 0, y: 0 };
  1. 函数类型别名
type Greeting = (name: string) => void;
let sayHello: Greeting = (name) => {
  console.log(`Hello, ${name}!`);
};

!!表达式

在 JavaScript 中,!! 是一种常见的语法结构,用于将一个值转换为布尔类型
它的作用是将任何数据类型的值转换为对应的布尔值

  1. 第一个否定运算符 !:它会将操作数的值转换为布尔类型,并返回相反的结果。
  2. 第二个否定运算符 !:它再次将上一步得到的布尔值取反,返回原始操作数的布尔类型。

非布尔类型的转换:
真值(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");
  }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GalenZhang888

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值