npm i -g typescript)注意:如果生成了 js 文件,ts 文件有变量重复声明的报错,可以执行
tsc -init命令,会生成一个 tsconfig.js 文件,如果有error TS2403: Subsequent variable declarations must have the same type. Variable 'AbortSignal' must be of type '{ new (): AbortSignal; prototype: AbortSignal; abort(reason?: any): AbortSignal; timeout(milliseconds: number): AbortSignal; }', but here has type '{ new (): AbortSignal; prototype: AbortSignal; }'.,或者declare var AbortSignal,或者Type 'Server' is not generic.报错,可以执行npm install @types/node -D
//声明一个变量a,同时指定它的类型为 number
//后续赋值或使用时,类型必须跟声明时的类型一致,否则会报错
let a : number;
a = 1;
//如果变了的声明和赋值时同时进行的,可以省略类型,ts 会自动对变量进行类型检测
//后续使用或赋值,同样要跟之前的类型一致,否则会报错
let b = true;
b = false;
//声明函数时,可以指定参数的类型
//调用函数时,入参类型要跟声明时的类型一致,另外,入参个数也要和函数声明时接收的参数个数一致
//函数声明时,括号后面也可以规定类型,该类型是函数返回值的类型
function sum (a: number, b: number): number{
return a + b
}
sum(123,456)
// sum(123,"456")·//报错
// sum(123,456,789)·//报错

let a : number;
a = 1;
let b = true;
b = false;
let e : any;
e = "12"
a = e
let f : unknown;
f = "1"
b = unknown //报错
//{}用来指定对象中可以包含哪些属性
//语法:{属性名:属性值,属性名:属性值}
//在属性名后加上?,表示属性是可选的,但是需要在定义时罗列出来
//使用[propname:string]:any,是上面?的简写,不需要一一罗列
//定义对象
let obj : {name: string, age? :number};
obj = {name: "张三",age: 18}
obj = {name: "张三"}
// let obj : {name: string,[propname:string]:any};
// obj = {name: "张三",age: 18, sex: "男"}
//设置数组的类型声明
//数组的类型声明:
// 类型[]
// Array<类型>
// let arr: string[]; //表示字符串数组
// arr = ["1","2"]
// let arr: number[]; //表示数字类型数组
// arr = [1,2]
let arr: Array<string>; //表示字符串数组
arr = ["1","2"]
//设置函数结构的类型声明:
//语法:(形参:类型,形参:类型......) => 返回值
// let d: () => any
let d: (a: number, b: number) => number
d = function (a, b) {
return a + b;
}
可以用来告诉解析器的实际类型。
语法:
let a : number;
a = 1;
let f : unknown;
f = 1
a = f as number
编译文件时,使用 -w 指令后,TS 编译器会自动监视文件的变化,并在文件变化时对文件进行重新编译,生成对应的 js 文件。
示例:
$ tsc demo.ts -w //监听某个ts文件并进行编译
$ tsc -w //检测整个目录中的ts文件并进行编译
tsc -init命令创建)["**/*"](** 表示任意目录,* 表示任意文件){
//src目录和test目录下的文件都会被编译
"include": [
"src/**/*",
"test/**/*"
]
}
["node-modules","bower_componts","jspm_packages"]{
//目录src下的所有文件都需要编译
"include": [
"src/**/*",
// "test/**/*"
],
//目录test下的所有文件都不需要编译
"exclude": [
"test/**/*"
]
}
//当前配置的文件中会自动包含 config 目录下的 base.json 中的所有配置信息
"extends": "./configs/base"
"files": [
"core.ts",
"sys.ts",
...
]
"compilerOptions": {
// target 用来指定 ts 被编译为的 ES 版本
//'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'es2021'...
"target": "ES5",
// module 指定要使用的模块化的规范
//“none","commonjs","amd","es6"...
"module": "commonjs",
// lib 指定代码运行时所包含的库(宿主环境)
"lib": [
"ES5",
"DOM"
],
// outDir 用来指定编译后文件所在的目录
"outDir": "./dist",
// outFile 将所有全局作用域中的代码合并到同一个文件中
// "outFile": "./dist/app.js"
// allowJs 师傅对 js 文件进行编译,默认是false
"allowJs": true,
// checkJs 是否以 ts 的标准去检查 js 代码是否符合语法规范,默认是 false
"checkJs": true,
// removeComments 生成的 js 文件是否需要移除注释
"removeComments": true,
// noEmit 执行编译过程,但是不生产编译后的文件,可用作代码检查
"noEmit": true,
// strict 下面所有严格检查的总开关
"strict": true,
// noEmitOnError 当有错误时,不生成编译后的文件
"noEmitOnError": false,
// alwaysStrict 用来设置编译后的文件是否使用严格模式
"alwaysStrict": true,
// noImplicitAny 不允许隐式的any类型
"noImplicitAny": true,
// noImplicitThis 不允许不明确类型的 this
"noImplicitThis": true,
// strictNullChecks 严格检查空值
"strictNullChecks": true
}
进入根目录,执行命令npm init -y,命令执行完会自动创建一个 package.json 文件
npm i -D webpack webpack-cli typescript ts-loader
配置打包的入口、出口和tsloader
const path = require("path")
module.exports = {
entry: "./src/main.ts",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
clean: true
},
module: {
rules: [
{
test: /\.ts$/,
use: "ts-loader",
exclude: /node_modules/
}
]
},
mode: "production"
}
{
"compilerOptions": {
"target": "ES2015",
"module": "ES2015",
"strict": true
}
}
"scripts": {
"build": "webpack"
},
function sum (a: number, b: number): number {
return a + b
}
console.log(sum(123,456));
npm run build
命令执行完,会在根目录下生成 dist/bundle.js 文件
直接定义的属性是实例属性,需要通过对象的实例去访问:
let per = new Person();
per.name
使用 static 开头的属性(方法)是静态属性(方法),或者类属性(方法),可以直接通过类去访问:
Person.job;
Person.sleep
readonly 开头的属性表示是只读属性,无法被修改
/*
直接定义的属性是实例属性,需要通过对象的实例去访问:
let per = new Person();
per.name
使用 static 开头的属性(方法)是静态属性(方法),或者类属性(方法),可以直接通过类去访问:
Person.job;
Person.sleep
readonly 开头的属性表示是只读属性,无法被修改
*/
class Person {
name: string = "张三";
age: number = 18
readonly sex = "男"
static job: string = "程序员";
eat() {
return "吃饭";
}
static sleep() {
return "睡觉";
}
}
let per = new Person()
console.log(per.name);
console.log(per.age);
console.log(Person.job);
console.log(per.eat());
console.log(Person.sleep());
class Dog{
name: string
age: number
//constructor 被称为构造函数
//构造函数会在对象创建时调用
constructor(name: string, age: number) {
//示例方法中,this表示当前的示例
//在构造函数中,当前对象就是当前创建的那个对象
//可以通过 this 向新建的对象中添加属性
this.name = name
this.age = age
}
eat() {
return "吃饭"
}
}
let dog1 = new Dog("小黑",5)
let dog2 = new Dog("小白", 6)
console.log(dog1);
console.log(dog2);
/**
* Dog extends Animal
* 此时,Animal 被称为 父类,Dog 被称为 子类
* 使用继承后,子类会拥有父类所有的方法和属性
* 使用继承,可以将多个类中共有的代码写在一个父类中
* 这样值需要写一次就可以让所有子类都同时拥有父类的属性
* 如果希望在子类中添加一些父类中没有的属性或者方法,可以在子类中直接加
* 如果在子类中添加了和父类相同的方法,则子类方法会覆盖父类的方法
* 这种子类覆盖掉父类的形式,称为 方法重写
*/
class Dog extends Animal {
talk(){
console.log("汪汪汪");
}
run() {
console.log(`${this.name}在跑`);
}
}
class Cat extends Animal {
talk(){
console.log("喵喵喵");
}
}
let dog = new Dog("小狗", 6)
let cat = new Cat("小猫", 8)
console.log(dog);
dog.talk()
dog.run()
console.log(cat);
cat.talk()

如果子类需要额外的属性,那么就要用到super(子类的构造函数中,调用父类构造函数,处理父类所需的属性)
否则,不需要用super
class Animal {
name: string
constructor(name: string) {
this.name = name
}
talk() {
console.log("动物在叫");
}
}
class Dog extends Animal {
age: number
constructor(name: string, age: number) {
//如果在子类中写了构造函数,在子类构造函数中必须对父类的构造函数进行调用
//如果不重写,默认会自动调用父类的构造函数
super(name) //调用父类的构造函数,传入父类构造函数所需要的参数
this.age = age
}
talk() {
//在类的方法中,super 就表示当前类的父类
// super.talk() //动物在叫
console.log("汪汪汪");
}
}
let dog = new Dog("小狗", 2)
console.log(dog);
dog.talk()
/**
* 以abstract开头的类是抽象类
* 抽象类和其他类区别不大,只是不能用来创建对象
* 抽象类就是专门用类被继承的类(父类)
*/
abstract class Animal {
name: string
constructor(name: string) {
this.name = name
}
//定义一个抽象方法
//抽象方法使用 abstract 开头,没有方法体
//抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写
abstract sayHello():void;
}
class Cat extends Animal {
sayHello() {
console.log("喵喵喵");
}
}
let cat = new Cat("小猫")
/**
* 接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法
* 同时接口也可以当成类型声明去使用
* 它是一种规范
*/
interface myInter {
name: string,
age: number
}
//如果定义同名的接口,接口数据会合并
interface myInter {
gender: string
}
let obj: myInter = {
name: "张三",
age: 18,
gender: "男"
}
/**
* 接口可以在定义类的时候去限制类的结构
* 接口中所有的属性都不能有实际的值
* 接口只定义对象的结构,而不考虑实际值
* 接口中所有的方法都是抽象方法
*/
interface myInterface {
name: string,
sayHello():void
}
/**
* 定义类是,可以使类去实现一个接口
* 实现接口就是使用类满足接口的要求
*/
class MyClass implements myInterface {
name: string
constructor(name: string) {
this.name = name
}
sayHello() {
console.log("你好啊");
}
}
let myclass = new MyClass("张三")
console.log(myclass);
TS 可以在属性前添加属性的修饰符
/**
* TS 可以在属性前添加属性的修饰符
* public 修饰的属性可以在任意位置(父类、子类、实例)访问(修改),是默认值
* private 私有属性,私有属性只能在类的内部访问(修改)
* - 通过在类中添加方法,是得私有属性可以被外部访问
* protected 受包含的属性,只能在当前类和当前类的子类中访问(修改)
*/
class Person {
name: string;
private _age: number;
private gender: string;
constructor(name: string, _age: number, gender: string) {
this.name = name;
this._age = _age;
this.gender = gender;
}
getGender() {
return this.gender
}
/**
* getter 方法分用来读取属性
* setter 方法用来设置属性
* 它们被称为属性的存取器
*/
get age() {
return this._age
}
set age(value: number) {
//使用 set 可以统一处理设置的值,如 name 属性则可以被任意修改,
//属性可以任意被修改会将导致对象中的数据变得非常不安全
if(value > 0) {
this._age = value
}
}
}
let per = new Person("张三", 20, "男")
per.age = 18
console.log(per.age);
console.log(per.getGender());
console.log(per);
// protected
class B {
protected num: number
constructor(num: number) {
this.num = num
}
}
class C extends B{
test() {
console.log("----"+this.num);
}
}
let c = new C(18)
c.test()
console.log(c.num); //受 protected 影响,实例无法访问 num
/**
* 在定义函数或类时,如果遇到类型不明确就可以使用泛型
*/
function fn<T>(a: T): T {
return a
}
//可以直接调用具有泛型的函数
fn(1); //不指定泛型,TS 可以自动对类型进行推断
fn<number>(1); //指定泛型
//泛型可以同时指定多个
function fn2<T, K>(a: T, b: K): T {
console.log(b);
return a
}
fn2("hello", 12);
fn2<string, number>("hello", 12);
interface inter {
length: number
}
//T extends inter 表示泛型 T 必须是 inter 实现类(子类)
function fn3<T extends inter>(a: T): number {
return a.length
}
class MyClass<T> {
name: T;
constructor(name: T) {
this.name = name
}
}
let mc = new MyClass<string>("张三")