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 语法。
<Type>
来进行类型断言,如下所示:let someValue: any = "Hello, TypeScript!";
let strLength: number = (<string>someValue).length;
在这个例子中,我们首先将 someValue
声明为 any
类型,然后使用尖括号 <string>
来告诉 TypeScript 编译器我们将 someValue
视为字符串类型,以便获取其 length
属性。
let someValue: any = "Hello, TypeScript!";
let strLength: number = (someValue as string).length;
需要注意的是,类型断言不会改变变量的实际类型,它只是在编译阶段告诉编译器如何处理这个变量。如果类型断言不正确,可能会导致运行时错误。因此,应该谨慎使用类型断言,尽量避免在不确定类型的情况下使用它们,而是更倾向于使用 TypeScript 提供的类型检查功能。
类型断言在以下情况常常使用:
类型别名:
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” 等)。
a.js: module.exports = {xxx:xxx}
const a=require('./a'); a.xxx
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:
compileOnSave:
typeAcquisition:
angularCompilerOptions:
references:
webpack打包ts工程文件
npm init -y
(y:yes,默认选项)npm i -D webpack webpack-cli typescript ts-loader
"scripts"
中添加"build":"webpack"
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
值。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 中非常强大和灵活的功能,它允许你编写更具通用性和可维护性的代码,并提供了强类型检查,有助于在编译时捕获潜在的错误。通过正确使用泛型,可以提高代码的可读性和可维护性,同时增加代码的复用性。