typescript学习笔记
-
js易学即是优点也是缺点
-
ts可以编译成各种版本的js
-
安装:npm i -g typescript
-
运行:tsc xxx.ts
-
变量类型声明:function sum(a:number):number{}
-
类型
- 基本类型:
number
:表示数值。string
:表示字符串。boolean
:表示布尔值。null
和undefined
:表示空值。symbol
:表示唯一的符号值。
- 复合类型:
array
:表示数组,可以使用泛型Array<T>
定义。let a:number[]
let a:Array<number>
tuple
:表示元组,允许你定义一个固定长度和固定类型的数组。- 因为固定,所以效率更高。
let a:[string, string]
object
:表示对象类型。- 常用于指明对象中包含什么属性。例如:
let a:{name:string,age?:number}
- 加?表示这个属性是可选的
- 必须存在某个属性其余属性随意 的写法:
let a:{name:string,[propName:string]:any}
propName:string表示任意字符串形式的的属性名,any表示任意类型
- 常用于指明对象中包含什么属性。例如:
function
:表示函数类型。- 常用于限制函数参数和返回值
- 写法:
let f:(a:number)=>number; f=function(n1){...}
enum
:表示枚举类型。- 枚举就像是一个标签集合,用来给一组特定的事物分配名字。这提高了代码的可读性和可维护性。
- 使用:
// Enum enum Color { Red, Green, Blue, } //或者显式赋值 enum Color { Red = 0, Green = 1, Blue = 2, } let color: Color = Color.Red; // 使用枚举成员 console.log(color); // 输出: 0 //存在数据库里的就是0而不是Red了
- 高级类型:
any
:表示任意类型,取消了类型检查。不写声明类型默认就是any。void
:表示没有返回值的函数。never
:表示永远不会返回结果的函数。不能返回值。unknown
:表示未知类型,相对于any
更加类型安全。原因:any类型的变量可以赋值给任何变量,会有隐患,unknown类型就不可以。union
:表示联合类型,可以包含多种不同类型的值。比如:let a:number|stringintersection
:表示交叉类型,可以包含多个类型的成员。
- 自定义类型:
- 使用
type
关键字来定义自定义类型。 - 使用
interface
关键字来定义接口。 字面量类型
:比如 let a:10;//a就只能是10。
- 补充
- 或:
let b:'male'|'female';
//b就只能赋这两个值 - 与:
let a:{name:string}&{age:number}
//等同于{name:string;age:number}
-
类型断言
类型断言是一种方式,允许你告诉编译器 “我知道这个变量的类型是什么”,从而可以绕过类型检查器的一些检查。类型断言有两种语法形式:angle-bracket 语法和 as 语法。- Angle-Bracket 语法:
使用尖括号<Type>
来进行类型断言,如下所示:
let someValue: any = "Hello, TypeScript!"; let strLength: number = (<string>someValue).length;
在这个例子中,我们首先将
someValue
声明为any
类型,然后使用尖括号<string>
来告诉 TypeScript 编译器我们将someValue
视为字符串类型,以便获取其length
属性。- as 语法:
let someValue: any = "Hello, TypeScript!"; let strLength: number = (someValue as string).length;
需要注意的是,类型断言不会改变变量的实际类型,它只是在编译阶段告诉编译器如何处理这个变量。如果类型断言不正确,可能会导致运行时错误。因此,应该谨慎使用类型断言,尽量避免在不确定类型的情况下使用它们,而是更倾向于使用 TypeScript 提供的类型检查功能。
类型断言在以下情况常常使用:
- 当你比编译器更了解某个值的类型时,例如在从 DOM 获取元素时。
- 当你需要与第三方库交互,这些库的类型信息不够完善时。
- 当你在编写自定义类型声明文件(.d.ts)时,需要告诉 TypeScript 如何处理某个库的类型。
- Angle-Bracket 语法:
-
类型别名:
type ID = number; type Point = { x: number; y: number }; type Person = { name: string; age: number }; // 使用类型别名 const userId: ID = 123; const userLocation: Point = { x: 10, y: 20 }; const personInfo: Person = { name: "Alice", age: 30 };
-
编译选项
tsc xxx.ts -w
watch,监视ts文件的变化反映到js上tsc
按照配置文件自动编译所有ts文件
tsconfig.json
是 TypeScript 项目的配置文件,用于指定
-
compilerOptions(编译器选项):
target
: 指定编译后的 JavaScript 版本(如 “ES5”, “ES6” 等)。module
: 指定模块的输出格式(如 “CommonJS”, “ES6” 等)。- commonJS和ES6的区别
- c:服务端,被引用的模块会被立即加载
- 出:
a.js: module.exports = {xxx:xxx}
- 入:
const a=require('./a'); a.xxx
- 出:
- 6:浏览器端,真正用到了才会加载
- 出:
b.js: export a=xxx
- 入:
import {a} from './b.js'
- 出:
outDir
: 指定编译后的 JavaScript 文件的输出目录。rootDir
: 指定 TypeScript 文件的根目录。strict
: 启用严格类型检查,包括strictNullChecks
,strictFunctionTypes
, 等。esModuleInterop
: 启用 ES 模块的互操作性。sourceMap
: 是否生成源映射文件。declaration
: 是否生成声明文件(.d.ts)。allowJs
: 允许编译 JavaScript 文件。默认falsecheckJs
: 是否按照ts规则检查js文件语法。默认falsenoEmit
: 不生成编译后的 JavaScript 文件,只进行类型检查。noEmitOnError
: 当有错误时,不编译lib
:用到了什么库(宿主环境),一般情况下不需要改
-
include 和 exclude:
include
: 包含哪些文件或文件夹进行编译,默认为项目根目录下的所有 TypeScript 文件。例如"./src/**/*"
表示src目录下的任意目录(**)
的任意文件(*)
exclude
: 排除哪些文件或文件夹不进行编译,默认为node_modules
,bower_components
,jspm_packages
等。
-
files:
- 明确指定要包括在编译中的文件列表。
-
extends:
- 引用其他 tsconfig.json 文件,当前配置文件会自动包含这个引用文件的配置选项。
-
compileOnSave:
- 是否在保存文件时自动触发编译。
-
typeAcquisition:
- 自动获取类型声明文件(如从 DefinitelyTyped)。
-
angularCompilerOptions:
- 用于 Angular 项目的编译选项。
-
references:
- 指定项目依赖关系,允许以多项目的方式构建和编译。
-
webpack打包ts工程文件
-
- 生成package.json配置文件
npm init -y
(y:yes,默认选项)
- 生成package.json配置文件
-
- 安装依赖
npm i -D webpack webpack-cli typescript ts-loader
- 安装依赖
-
- 编写webpack.config.js配置文件
-
- 编写package.json在
"scripts"
中添加"build":"webpack"
- 编写package.json在
-
- 开始打包:npm run build
-
-
babel的作用
将最新版本ECMAScript规范(例如ES6、ES7、ES8等)编写的JavaScript代码,转译成可以在不同浏览器中运行的旧版本JavaScript代码。从而实现浏览器兼容。 -
TS中的类:
- 类的定义:
在TS中,你可以使用
class
关键字来定义一个类。例如:class Person { // 属性 firstName: string; lastName: string; // 构造函数 constructor(firstName: string, lastName: string) { this.firstName = firstName; this.lastName = lastName; } // 方法 getFullName() { return `${this.firstName} ${this.lastName}`; } }
这个类定义了一个
Person
类,具有firstName
和lastName
属性以及一个getFullName
方法。- 创建类的实例:
一旦类被定义,你可以使用
new
关键字来创建该类的实例:const person = new Person("John", "Doe");
- 属性和方法:
类中可以包含属性和方法。属性用于存储数据,而方法用于执行操作。在类中的方法可以访问类的属性。
- 构造函数:
构造函数用于在创建类的实例时初始化对象的属性。它在对象创建时自动调用。在上面的例子中,
constructor
方法用于初始化firstName
和lastName
属性。- 访问修饰符:
TS支持访问修饰符,例如
public
、private
和protected
,用于控制属性和方法的访问权限。默认情况下,类的成员是public
的,这意味着它们可以在类的外部访问。你可以使用访问修饰符来限制成员的访问权限。- 继承:
TS支持类的继承,一个类可以继承另一个类的属性和方法。继承使用
extends
关键字实现。例如:class Employee extends Person { employeeId: number; constructor(firstName: string, lastName: string, employeeId: number) { super(firstName, lastName); // 调用父类的构造函数 this.employeeId = employeeId; } // 可以重写父类的方法 getFullName() { return `${super.getFullName()} (Employee ID: ${this.employeeId})`; } }
- 静态属性和方法:
你可以使用
static
关键字定义静态属性和方法,它们属于类本身而不是类的实例。class MathUtility { static PI: number = 3.14159; static calculateCircleArea(radius: number) { return MathUtility.PI * radius * radius; } }
使用方式如下:
const area = MathUtility.calculateCircleArea(5);
-
抽象类:
TS支持抽象类,它们不能被实例化,但可以被其他类继承。抽象类通常用于定义基类,其中包含一些共享的属性和方法的框架。abstract class Shape { abstract getArea(): number; }
子类必须实现抽象类中定义的抽象方法。
这些是 TypeScript 中类的一些基本概念和用法。类是面向对象编程的核心概念之一,可以帮助你更好地组织和抽象代码,使其更易于维护和扩展。
-
接口:
在 TypeScript 中,接口(Interfaces)是一种用于定义对象的结构或形状的抽象化工具。接口用于描述对象应该具备的属性和方法,以便在编写代码时进行类型检查,确保对象符合指定的结构。接口在 TypeScript 中非常有用,特别是在面向对象编程和编写可重用代码时。
以下是关于 TypeScript 接口的一些基本概念和用法:- 接口的定义:
使用
interface
关键字来定义接口。接口描述了一个对象的属性和方法的结构,但不提供实现。例如:interface Person { firstName: string; lastName: string; getFullName(): string; }
这个
Person
接口定义了一个对象应该包含firstName
和lastName
属性,以及一个getFullName
方法。- 对象符合接口:
在 TypeScript 中,对象可以符合(或实现)接口,只要对象的结构与接口的结构匹配,就可以将该对象视为符合该接口。例如:
const person: Person = { firstName: "John", lastName: "Doe", getFullName() { return `${this.firstName} ${this.lastName}`; } };
这个
person
对象符合Person
接口的结构。- 可选属性:
接口中的属性可以标记为可选,使用
?
符号。这意味着对象可以包含该属性,也可以不包含。例如:interface Car { make: string; model: string; year?: number; // year 是可选属性 }
const myCar: Car = { make: "Toyota", model: "Camry" };
- 只读属性:
使用
readonly
关键字可以将接口属性标记为只读,这意味着属性的值在对象创建后不能被修改。例如:interface Point { readonly x: number; readonly y: number; }
const point: Point = { x: 10, y: 20 }; // point.x = 30; // 编译错误,无法修改只读属性
- 函数类型:
接口可以描述函数类型,包括函数参数和返回值的类型。例如:
interface CalculateArea { (radius: number): number; }
这个接口描述了一个函数类型,接受一个
number
类型的参数并返回一个number
类型的值。- 继承接口:
TypeScript 支持接口之间的继承。一个接口可以继承另一个接口的属性和方法。例如:
interface Person { firstName: string; lastName: string; } interface Employee extends Person { employeeId: number; }
Employee
接口继承了Person
接口的属性。- 类实现接口:
类可以通过
implements
关键字来实现接口,以确保类符合接口定义的结构。例如:class Employee implements Person { firstName: string; lastName: string; employeeId: number; constructor(firstName: string, lastName: string, employeeId: number) { this.firstName = firstName; this.lastName = lastName; this.employeeId = employeeId; } getFullName() { return `${this.firstName} ${this.lastName}`; } }
Employee
类实现了Person
接口的结构。接口在 TypeScript 中是一种非常有用的工具,它有助于增强代码的可读性和可维护性,同时可以进行静态类型检查,帮助开发者在开发过程中捕获潜在的错误。它们经常用于定义合同和规范,以确保不同部分的代码能够协同工作。
-
this的指向问题:
在 JavaScript 和 TypeScript 中,构造函数中的
this
关键字的指向是一个重要且常见的概念。理解this
的指向对于正确编写和理解对象的创建和初始化非常关键。以下是一些关于构造函数中this
指向的重要概念:- 默认绑定:
- 在普通函数中,
this
默认绑定到全局对象(在浏览器中通常是window
对象),这意味着在全局范围内使用this
会指向全局对象。
function sayHello() { console.log("Hello, " + this.name); } const name = "Global"; sayHello(); // 输出 "Hello, Global"
- 在严格模式下,全局对象不会被用作默认绑定,而是
this
会被设置为undefined
。
"use strict"; function sayHello() { console.log("Hello, " + this.name); } const name = "Global"; sayHello(); // 输出 "Hello, undefined"
- 隐式绑定:
- 当函数作为对象的方法被调用时,
this
会隐式绑定到调用该方法的对象。
const person = { name: "John", sayHello() { console.log("Hello, " + this.name); } }; person.sayHello(); // 输出 "Hello, John"
- 显式绑定:
- 你可以使用
call()
、apply()
或bind()
方法来显式绑定this
到指定的对象。
function sayHello() { console.log("Hello, " + this.name); } const person = { name: "John" }; sayHello.call(person); // 使用 call() 显式绑定 sayHello.apply(person); // 使用 apply() 显式绑定 const boundSayHello = sayHello.bind(person); // 使用 bind() 创建绑定的函数 boundSayHello();
- 箭头函数中的 this:
- 箭头函数的
this
始终继承自包含它的最近的非箭头函数父作用域。它不具备自己的this
,而是捕获了父作用域的this
值。
const person = { name: "John", sayHello: () => { console.log("Hello, " + this.name); // this 指向全局对象,不是 person 对象 } }; person.sayHello(); // 输出 "Hello, undefined"
-
泛型:把类型作为一种参数:
泛型(Generics)是 TypeScript 中的一个重要特性,它允许你编写可重用的、灵活的代码,同时提高代码的类型安全性。泛型允许你在编写函数、类和接口时,将类型作为参数进行参数化,以便在不同地方使用相同的代码,但可以适用于不同的数据类型。
以下是有关泛型的基本概念和用法:
- 泛型函数:
在函数中使用泛型可以使函数接受不同类型的参数,同时确保正确的类型检查。例如,下面是一个泛型函数,用于交换两个值:
function swap<T>(a: T, b: T): [T, T] { return [b, a]; } const result = swap(1, 2); // result 的类型为 [number, number]
在这个示例中,
<T>
表示类型参数,它允许我们将不同类型的值传递给swap
函数,同时保留了类型的一致性。- 泛型类:
你可以创建泛型类,允许类的属性或方法使用泛型类型。例如:
class Box<T> { private value: T; constructor(value: T) { this.value = value; } getValue(): T { return this.value; } } const numberBox = new Box<number>(42); const stringBox = new Box<string>("Hello");
这里的
Box
类是一个泛型类,它可以用不同的类型参数实例化,从而创建不同类型的盒子。- 泛型接口:
泛型也可以用于接口的定义,以便在创建实现该接口的类时指定类型参数。例如:
interface Pair<T, U> { first: T; second: U; } const pair: Pair<number, string> = { first: 1, second: "two" };
这个示例中,
Pair
接口接受两个类型参数T
和U
,并且我们可以在使用该接口的时候指定具体的类型。- 泛型约束:
有时候你想要对泛型类型进行一些限制,确保它具有特定的方法或属性。你可以使用泛型约束来实现这一点。例如:
function lengthOfValue<T extends { length: number }>(value: T): number { return value.length; } const strLength = lengthOfValue("Hello"); // 5 const arrLength = lengthOfValue([1, 2, 3]); // 3 // const numLength = lengthOfValue(42); // 编译错误,数字没有 length 属性
这里的
<T extends { length: number }>
表示T
必须是具有length
属性的对象类型,这样我们可以安全地访问value.length
。泛型是 TypeScript 中非常强大和灵活的功能,它允许你编写更具通用性和可维护性的代码,并提供了强类型检查,有助于在编译时捕获潜在的错误。通过正确使用泛型,可以提高代码的可读性和可维护性,同时增加代码的复用性。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!