安装
安装
npm install -g typescript
检测安装是否成功
tsc -V
编译
手动编译
对于 xxx.ts 文件,执行
tsc xxx.ts
输出为 xxx.js 文件,将ts文件里面的代码转成js代码
通过node.js 运行代码
node xxx.js
自动编译
1). 生成配置文件tsconfig.json
tsc --init
2). 修改tsconfig.json配置
"outDir": "./js", ts文件编译后的js文件会在./js目录下
"strict": false, 非严格模式
3). 启动监视任务:
终端 -> 运行任务 -> 监视tsconfig.json
webpack打包
下载依赖package.json
{
"name": "ha", // 自命名
"version": "0.1.0",
"description": "",
"main": "index.js",
"scripts": {
// 配置打包命令
"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.js",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/jquery": "^3.5.4", // 下载jquery的声明文件
"clean-webpack-plugin": "^3.0.0",
"cross-env": "^7.0.2",
"html-webpack-plugin": "^4.5.0",
"ts-loader": "^8.0.11",
"typescript": "^4.0.5",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.2",
"jquery": "^3.6.0" // 安装jquery
}
}
入口JS: src/main.ts
document.write('Hello Webpack TS!')
index页面: public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>webpack & TS</title>
</head>
<body>
</body>
</html>
build/webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
const isProd = process.env.NODE_ENV === 'production' // 是否生产环境
function resolve (dir) {
return path.resolve(__dirname, '..', dir)
}
module.exports = {
mode: isProd ? 'production' : 'development',
entry: {
app: './src/main.ts'
},
output: {
path: resolve('dist'),
filename: '[name].[contenthash:8].js'
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
include: [resolve('src')]
}
]
},
plugins: [
new CleanWebpackPlugin({
}),
new HtmlWebpackPlugin({
template: './public/index.html'
})
],
resolve: {
extensions: ['.ts', '.tsx', '.js']
},
devtool: isProd ? 'cheap-module-source-map' : 'cheap-module-eval-source-map',
devServer: {
host: 'localhost', // 主机名
stats: 'errors-only', // 打包日志输出输出错误信息
port: 8089,
open: true
},
}
运行与打包
与配置的命令有关
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.js",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
}
npm run dev
npm run build
类型注解
function greeter (person: string) {
return 'Hello, ' + person
}
let user = 'Yee'
console.log(greeter(user))
约束变量person的类型为string,编译时即使存在错误,也会生成相应的js文件
基础类型
基本语法: let 变量名:数据类型 = 值
boolean
let boo1:boolean = true;
let boo2 = false;
console.log(boo1,'--',boo2) // true "--" false
number
let num1: number = 10 // 十进制
let num2: number = 0b1010 // 二进制
let num3: number = 0o12 // 八进制
let num4: number = 0xa // 十六进制
console.log(num1,'-',num2,'-',num3,'-',num4) // 10 "-" 10 "-" 10 "-" 10
string
let name:string = 'tom'
console.log(`My name is ${name}, I am ${num1} years old!`) // My name is tom, I am 10 years old!
undefined null
undefined null 可以被赋值给任意类型,算是其他类型的子类型(非严格模式)
let un1: undefined = undefined
let nu1: null = null
num1 = null
console.log(un1,'-',nu1) // undefined "-" null
console.log(`num1=${num1}`) // num1=null
数组 array
语法:
let 变量名: 数据类型[] = [值...]
let 变量名: Array<数据类型> = [值...]
值的类型必须是定义的数据类型,否则会报错
let arr1: number[] = [1,2,3]
let arr2: Array<number> = [4,5,6]
console.log(arr1,'---',arr2) // (3) [1, 2, 3] "---" (3) [4, 5, 6]
元祖 tuple
定义数组的时候限定数据的位置、类型与个数
let arr3: [string, number, boolean] = ['haha',10,true]
console.log(arr3) // (3) ["haha", 10, true]
枚举
枚举里面的每个数据都可以称为元素,每个元素都有自己的编号,默认从0开始,依次递增,也可以自定义,元素可以是中文(不推荐)
enum Color{
red = 10,
绿 = 9,
blue,
orange
}
let color: Color = Color.blue
console.log(color,'-',Color.绿,'--',Color.red) // 10 "-" 9 "--" 10
console.log(Color) // {9: "绿", 10: "blue", 11: "orange", red: 10, 绿: 9, blue: 10, orange: 11}
any
不确定具体类型时使用,也可用于数组中(any[]
或者 Array<any>
)
let any1: any = 1
any1 = 'haha'
console.log(any1) // haha
// let any2: any[] = [100,'jjadsasdfghj',true]
let any2: Array<any> = [100,'jjadsasdfghj',true]
console.log(any2[1].split(''))
// console.log(any2[0].split(''))
// 编译时不会报错,但在浏览器中会报错Uncaught TypeError: any2[0].split is not a function
void
函数声明的时候,在小括号的后面使用:void
,表示该函数没有返回值
function show(): void {
// return // undefined
// return undefined // undefined
return null // null
// return 1 // error
}
console.log(show())
let vo1: void = undefined
let vo2: void = null
console.log(vo1,'----',vo2) // undefined "----" null
object
// object:定义一个函数,参数与返回值都是object类型
function getObj(x: object): object {
console.log(x)
return {
name: 'ni',
age: 10
}
// return null或者undefined也可以
}
console.log(getObj({name: 'haha', age: 26})) // {name: "haha", age: 26} {name: "ni", age: 10}
console.log(getObj({})) // {} {name: "ni", age: 10}
console.log(getObj(new String(123))) // String {"123"} {name: "ni", age: 10}
console.log(getObj(String)) // ƒ String() { [native code] } {name: "ni", age: 10}
联合类型 Union Types
取值可以为多种类型中的一种 |
// x 取值只能为数字 或 字符串,其他类型会报错
let x: number | string = 100
x = 'uuu'
// x = true // Type 'boolean' is not assignable to type 'string | number'.
类型断言 Type Assertion
手动指定一个值的类型
语法:
-
<类型>值
-
值 as 类型
tsx 中只能用这种方式
function getLength(x: number | string) {
// 如果是string类型,直接返回x.length比较简单,但number没有length属性,直接用会报错,所以要用到类型断言
return (<string>x).length ? (x as string).length : x.toString().length
}
console.log(getLength('hahagdssdfgh'),'---',getLength(12345)) // 12 "---" 5
类型推断
当没有明确指定类型的时候推测出一个类型
-
定义变量时赋值了, 推断为对应的类型
let b9 = 123 // number // b9 = 'abc' // error 不能将类型“string”分配给类型“number” console.log(b9)
-
定义变量时没有赋值, 推断为any类型
let b10 // 变量 "b10" 隐式具有 "any" 类型,但可以从用法中推断出更好的类型 b10 = 123 b10 = 'abc' console.log(b10)
接口
相当于一个约束,interface中定义的属性必须传,不传会报错,编译成js文件后执行会显示为undefined
如果多传一个属性不会报错
interface Person {
firstName: string,
lastName: string
}
function person(person: Person) {
console.log(person.firstName,'--',person.lastName)
}
let user = {
firstName: 'haha',
lastName: 'ben'
}
person(user)
基础
接口是对象的状态(属性)和行为(方法)的抽象(描述)
只读,可选属性
-
readonly 只读
— 作为变量使用的话用const
,若作为属性则使用readonly
-
? 可选
— 可选属性的好处之一是可以对可能存在的属性进行预定义,好处之二是可以捕获引用了不存在的属性时的错误。
interface Person {
readonly id: number
name: string
age: number
sex?: string
}
const person: Person = { // 定义属性必须与接口一致,不能多属性少属性
id: 1,
name: 'haha',
age: 18,
// sex: '女', 可选属性
}
// person.id = 10 无法分配到 "id" ,因为它是只读属性
console.log(person)
函数类型
为了使用接口表示函数类型,我们需要给接口定义一个调用签名
。
它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。
// 定义的接口,用作searchF函数的类型使用
interface searchFunc {
// 调用签名: 括号内是要传的参数,boolean便是返回值类型
(a: string, b: string): boolean
}
// 定义函数,该类型就是上面定义的接口
const searchF: searchFunc = function (a: string, b: string): boolean {
// 在字符串a中查找b这个字符串,search会返回b在a中所处位置,没有则返回 -1
return a.search(b)> -1
}
console.log(searchF('hhhhaaa','h'))
类类型
使用接口来实现类的类型
类可以实现一个接口,也可以实现多个接口。接口中的内容都要真正地实现
类实现一个接口
// 定义一个接口
interface IFly {
fly() // 该方法中没有任何的实现
}
// 定义一个类,该类型是上面定义的接口(IFly接口约束了Person1类)
class Person1 implements IFly {
// 实现接口中的方法
fly() {
console.log('fly1')
}
}
const person1 = new Person1() // 实例化对象
person1.fly() // fly1
类实现多个接口
interface ISwim {
swim()
}
// 定义一个类,其类型是IFly和ISwim(当前这个类可以实现多个接口,一个类也可以同时被多个接口约束)
class Person2 implements IFly,ISwim {
fly() {
console.log('fly2')
}
swim() {
console.log('swim2')
}
}
const person2 = new Person2()
person2.fly() // fly2
person2.swim() // swim2
接口继承
接口与接口之间叫继承(使用extends关键字),类和接口之间叫实现(使用implements)
// 定义一个接口,继承其他的多个接口
interface IflyAndSwim extends IFly,ISwim {}
// 定义一个类,直接实现IflyAndSwim这个接口
class Person3 implements IflyAndSwim {
fly() {
console.log('fly3')
}
swim() {
console.log('swim3')
}
}
const person3 = new Person3()
person3.fly() // fly3
person3.swim() // swim3
类
类:相当于模板,通过模板可以实例化对象
基本示例
interface IPerson {
firstName: string,
lastName: string
}
function showPerson(person: IPerson) {
console.log(person.firstName + '--' + person.lastName)
}
class CPerson {
// 公共字段(属性)
firstName: string
lastName: string
fullName: string
// 构造器函数
constructor (firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
this.fullName = firstName + '_' + lastName;
}
}
// 通过类来实例化对象,不直接定义一个对象
let user = new CPerson('haha', 'aaa')
showPerson(user) // haha--aaa
TypeScript 里的类只是一个语法糖,本质上还是 JavaScript 函数的实现。
编译成的js代码:
function showPerson(person) {
console.log(person.firstName + '--' + person.lastName);
}
var CPerson = /** @class */ (function () {
function CPerson(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.fullName = firstName + '_' + lastName;
}
return CPerson;
}());
var user = new CPerson('haha', 'aaa');
showPerson(user);
同一文件夹下定义的变量名不要重复,即使 ts 文件中用的是 let,但编译成 js 是 var – 全局变量,会报错。每次的 ts 文件写成立即执行函数可以用相同变量名
// 面向对象
class Person {
// 定义属性
name: string
age: number
gender: string
// 定义构造函数:将来实例化对象时,可以直接对属性的值进行初始化
constructor (name: string='haha', age: number=17, gender: string='女') {
// 更新对象中的属性数据
this.name = name
this.age = age
this.gender = gender
}
// 定义实例方法
show(str: string) {
console.log(`I am ${this.name}, ${this.age} years old, ${this.gender}`,str)
}
}
// 通过类实例化对象,可以直接进行初始化操作
let person = new Person('aa',20,'男') // new Person()传参时:I am aa, 20 years old, 男 and you?
person.show('and you?'); // new Person()不传参时:I am haha, 17 years old, 女 and you?
继承extends
类和类之间有继承关系时,使用extends
关键字
子类( 派生类 )调用父类( 基类 — 超类 )中的构造函数与实例方法时,使用super
关键字
子类可以重写父类的方法
// 类Huang(子类 --- 派生类)继承自Person类(基类 --- 超类)
class Huang extends Person {
constructor (name: string, age: number, gender: string) {
// 调用基类中的构造函数,使用super
super(name, age, gender)
}
show1() {
// 调用父类中的方法
super.show('你好!')
}
}
let huang = new Huang('小明',24,'男')
huang.show1() // I am 小明, 24 years old, 男 你好!
多态
父类型引用指向子类型的实例 ==> 多态
如果子类型没有扩展的方法(除了父类中的方法,没有额外的实例方法), 可以让子类型引用指向父类型的实例
如果子类型有扩展的方法, 不能让子类型引用指向父类型的实例
父类型的引用指向了子类型的对象,不同类型的对象针对相同的方法,产生了不同的行为
class Animal {
name: string
constructor (name: string) {
this.name = name
}
run(distance: number = 0) {
console.log(`${this.name} run ${distance}米`)
}
}
class Dog extends Animal {
constructor (name: string) {
super(name)
}
// 重写父类中的实例方法
run(distance: number = 5) {
console.log(`${this.name} run ${distance}米`)
}
}
class Pig extends Animal {
constructor (name: string) {
super(name)
}
run(distance: number = 10) {
console.log(`${this.name} run ${distance}米`)
}
}
const ani: Animal = new Animal('动物')
ani.run() // 动物 run 0米
const dog: Dog = new Dog('汪汪')
dog.run() // 汪汪 run 5米
const pig: Pig = new Pig('哼哼')
pig.run() // 哼哼 run 10米
// 父级类型创建子类的对象
const dog1: Animal = new Dog('柴犬')
dog1.run() // 柴犬 run 5米
const pig1: Animal = new Pig('两头乌')
pig1.run() // 两头乌 run 10米
function showAnimal (ani: Animal) {
ani.run() // 参数需要是Animal类型的,但是传的子类改写了Animal的run方法
}
showAnimal(dog1) // 柴犬 run 5米
showAnimal(pig1) // 两头乌 run 10米
修饰符public private protected readonly
修饰符:描述类中成员(属性、构造函数、方法)的可访问性
-
public
默认 — 公共的,任何位置都可以访问类中的成员 -
private
— 私有的,外部与子类均无法访问 -
protected
— 受保护的,外部无法访问,子类中可以访问
对构造函数中的参数用 public private protected 修饰,相当于类中自动添加属性成员
readonly
只读属性必须在声明时或构造函数里被初始化。
类中的属性成员用readonly
修饰后,该属性成员在外部不可随意修改,在构造函数中可以修改
构造函数中的参数用readonly
进行修饰(也叫 参数属性),constructor (readonly name: string)
创建和初始化属性成员readonly name: string
class Animal {
public name: string
// private name: string
// protected name: string
constructor (name: string) {
this.name = name
}
}
class Dog extends Animal {
constructor (name: string) {
super(name)
}
showParent() {
console.log(this.name) // 子类中访问属性
}
}
const dog: Dog = new Dog('汪汪')
// 外部访问属性
console.log(dog.name) // public: 汪汪 private:属性“name”为私有属性,只能在类“Animal”中访问。 protected: 属性“name”受保护,只能在类“Animal”及其子类中访问
dog.showParent() // public: 汪汪 private:属性“name”为私有属性,只能在类“Animal”中访问。 protected: 汪汪
存取器
存取器:可以有效地控制对象中成员的访问,通过getters
和setters
来进行操作
class GSPerson {
firstName: string
lastName: string
constructor(firstName: string, lastName: string) {
this.firstName = firstName
this.lastName = lastName
}
// 读取器:读取数据
get fullName() {
console.log('get...')
return this.firstName + '-' + this.lastName
}
// 设置器:修改数据
set fullName(val) {
console.log('set...')
let temp = val.split('-')
this.firstName = temp[0]
this.lastName = temp[1]
}
}
const gs = new GSPerson('东方','不败')
console.log(gs.fullName) // get... 东方-不败
gs.fullName = '诸葛-孔明' // set...
console.log(gs.fullName) // get... 诸葛-孔明
静态成员static
静态成员:这些属性存在于类本身上面而不是类的实例上
静态属性, 是类对象的属性
非静态属性, 是类的实例对象的属性
在类中通过static
修饰的属性或者方法(静态属性与静态方法)
静态成员使用:类名.
class staPerson {
// 不能用name属性: 静态属性“name”与构造函数“staPerson”的内置属性函数“name”冲突
static age: number = 10
// “static”修饰符不能出现在构造函数声明中
// static constructor(age1: number) {
// // this是实例对象,age是静态属性,不能通过实例对象直接调用静态属性
// // this.age = age1 // 属性“age”不是类型为“staPerson”的静态成员
// }
static sayHi() {
console.log('hello')
}
}
// const sta = new staPerson()
// 通过实例对象调用的属性(实例属性)
// console.log(sta.age) // 报错:属性“age”不是类型为“staPerson”的静态成员。 编译后显示:undefined
// 通过实例对象调用的方法(实例方法)
// sta.sayHi()
// 通过 类名.静态属性 的方法来访问该成员数据
console.log(staPerson.age) // 10
// 通过 类名.静态属性 的方法来设置该成员数据
staPerson.age = 20
console.log(staPerson.age) // 20
// 通过 类名.静态属性 的方法来调用内部静态方法
staPerson.sayHi() // hello
抽象类abstract
抽象类:包含抽象方法(抽象方法一般没有任何的具体内容的实现),也可以包含实例方法
抽象类不能被实例化,为了让子类进行实例化及实现内部的抽象方法
抽象类最终都是为子类服务的
abstract class cAnimal {
abstract name: string = '大灰狼' // 抽象属性
// 抽象方法
abstract eat() // 方法“eat”不能具有实现,因为它标记为抽象。
// 实例方法
run() {
console.log('跑呀')
}
}
// const dogg: cAnimal = new cAnimal() // 无法创建抽象类的实例
// 定义子类(派生类)
class Dogg extends cAnimal {
name: string = '狗狗'
// 如果不写eat方法报错:非抽象类“dogg”不会实现继承自“cAnimal”类的抽象成员“eat”。
// 重新写基类中的抽象方法,相当于子类中的实例方法
eat() {
console.log('吃骨头')
}
}
const dogg: Dogg = new Dogg()
dogg.eat() // 吃骨头
// 调用抽象类中的实例方法
dogg.run() // 跑呀
console.log(dogg.name) // 狗狗
函数
函数:封装了一些重复使用的代码,在需要的时候直接调用即可
基本示例
// 函数声明 --- 命名函数
function add(x: string, y: string): string {
return x + y
}
console.log(add('11','44')) // 1144
// 函数表达式 --- 匿名函数
// ?可选参数,x默认参数为10,如果不传入则采用默认值
let a = function (x: number = 10, y?: number): number {
return x + y
}
console.log(a(11,44)) // 55
函数完整表达式
// b ---> 变量名 ---> 函数b
// (x: number, y: number) => number 当前函数的类型
// function(x: number, y: number): number {return x + y} 相当于符合上面函数类型的值
let b:(x: number, y: number) => number = function(x: number, y: number): number {
return x + y
}
console.log(b(11,44)) // 55
剩余参数
剩余参数:放在参数声明的最后
// ...args: string[] 剩余的参数放在了一个字符串的数组中
function show(x: string, ...args: string[]) {
console.log(x) // a
console.log(args) // (4) ['b', 'v', 'f', 'jkgfdsa']
}
show('a','b','v','f','jkgfdsa')
函数重载
函数重载:函数名字相同,函数参数及个数不同
// 需求:字符串类型的拼接,数字类型相加
function addMix(x: string, y: string): string
function addMix(x: number, y: number): number
function addMix(x: string | number, y: string | number): string | number {
// x y类型必须一直才能进行接下来的操作
if(typeof x === 'string' && typeof y === 'string') {
return x + y
} else if(typeof x === 'number' && typeof y === 'number') {
return x + y
}
}
console.log(addMix('hah','a')) // haha
console.log(addMix(13,5)) // 18
// console.log(addMix('hah',13)) // undefined 没有重载时会显示为“undefined”,声明重载后“没有与此调用匹配的重载”
// console.log(addMix(4,'a')) // undefined
泛型
泛型:在定义函数、接口、类的时候不能预先确定要使用的数据类型,在使用函数、接口、类的时候才能确定数据类型
基本示例
需求:根据指定的数量 count 和数据 value , 创建一个包含 count 个 value 的数组
非泛型:
function getArr(x: any, y: number): any[] {
const arr: any[] = []
for(let i = 0; i < y; i++) {
arr.push(x)
}
return arr
}
const a = getArr(10.8751,4)
const b = getArr('ab',4)
// 非泛型的时候没有智能提示
console.log(a,a[0].toFixed(2)) // [10.8751, 10.8751, 10.8751, 10.8751] '10.88'
console.log(b,b[0].split('')) // ['ab', 'ab', 'ab', 'ab'] (2) ['a', 'b']
泛型:类型表示为 <类型别称>
function getArr1<T>(x: T, y: number): T[] {
const arr: T[] = []
for(let i = 0; i < y; i++) {
arr.push(x)
}
return arr
}
const a1 = getArr1<number>(8.9876543,4)
const b1 = getArr1<string>('abcdss',4)
// 非泛型的时候没有智能提示
console.log(a1,a1[0].toFixed(2)) // [8.9876543, 8.9876543, 8.9876543, 8.9876543] '8.99'
console.log(b1,b1[0].split('')) // ['abcdss', 'abcdss', 'abcdss', 'abcdss'] ['a', 'b', 'c', 'd', 's', 's']
多个泛型参数的函数
function getDouble<K,V>(x: K, y: V): [K, V] {
return [x, y]
}
const d = getDouble<string, number>('dfgh',18.098765)
console.log(d[0].split(''),'---',d[1].toFixed(2)) // ['d', 'f', 'g', 'h'] '---' '18.10'
泛型接口
泛型接口:在定义接口时, 为接口中的属性或方法定义泛型类型;在使用接口时, 再指定具体的泛型类型
需求:定义一个类,用来存储用户的相关信息(id,名字,年龄)
通过一个类的实例对象调用add方法可以添加多个用户信息对象,调用gerUserId方法获取指定id的用户信息
// 定义一个类,用来存储用户的相关信息(id,名字,年龄)
class User{
id?: number
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
// 定义一个类,增加add gerUserId方法
// 如果不是User类型而是其他类型每次重复代码不好,所以定义个“泛型接口”
interface IBaseCRUD<T> {
data: Array<T>
add: (t: T) => T
gerUserId:(id: number) => T
}
class UserCRUD implements IBaseCRUD<User>{
// data保存多个User类型的用户信息
data: Array<User> = []
add(user: User):User {
user.id = Date.now() + Math.random()
this.data.push(user) // 用户信息添加到data数组中
return user
}
gerUserId(id: number): User {
return this.data.find(item => item.id === id)
}
}
const u1 = new UserCRUD()
// 调用添加数据的方法
u1.add(new User('哈',19))
u1.add(new User('a',12))
u1.add(new User('qw',16))
u1.add(new User('zxc',34))
u1.add(new User('gh',23))
console.log(u1.data) // 打印出总共6条数据
// 根据id查询数据信息
const { id } = u1.add(new User('zxcv',12))
console.log(u1.gerUserId(id)) // User {name: 'zxcv', age: 12, id: 1631879418881.0364}
泛型类
泛型类:在定义类时, 为类中的属性或方法定义泛型类型;在创建类的实例时, 再指定特定的泛型类型
class GenericNumber<T> {
default: T
add: (x: T, y: T) => T
}
const g1: GenericNumber<number> = new GenericNumber<number>()
// 设置默认属性值
g1.default = 12
// 定义add方法
g1.add = function (x, y) {
return x + y
}
console.log(g1.add(13,8)) // 21
const g2: GenericNumber<string> = new GenericNumber<string>()
// 设置默认属性值
g2.default = 'hgfd'
// 定义add方法
g2.add = function (x, y) {
return x + y
}
console.log(g2.add(g2.default,'kjh')) // hgfdkjh
泛型约束
泛型约束: 如果我们直接对一个泛型参数取 length 属性, 会报错, 因为这个泛型根本就不知道它有这个属性
需要定义一个接口,用来约束将来的类型中必须有length属性
interface ILength {
length: number
}
function getLength<T extends ILength>(x: T): number {
return x.length
}
console.log(getLength<string>('kjhgfdswertyui')) // 14
声明文件
当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能
声明语句: declare var jQuery: (selector: string) => any
声明文件:把声明语句单独放到一个文件内,命名xxx.d.ts
,不用引入,ts自动解析
npm下载声明文件:npm install @types/jquery --save-dev
下载的声明文件JQuery.d.ts
在 node_modules/@types/jquery
// 引入第三方的库jQuery
import jQuery from 'jquery'
// 声明语句
// declare var jQuery: (selector: string) => any
// 使用jQuery
jQuery('选择器')
内置对象
内置对象是指根据标准在全局作用域(Global)上存在的对象。这里的标准是指 ECMAScript 和其他环境(比如 DOM)的标准。
ECMAScript 的内置对象
- Boolean
- Number
- String
- Date
- RegExp
- Error
let b: Boolean = new Boolean(1) // Boolean {true}
let n: Number = new Number(true) // Number {1}
let s: String = new String('abc') // String {'abc'}
let d: Date = new Date() // Sat Sep 18 2021 16:07:05 GMT+0800 (中国标准时间)
let r: RegExp = /^1/ // /^1/
let e: Error = new Error('error message') // Error: error message
// b = true // b是单纯的boolean值,不是对象
console.log(new Number(false),new Number(1),new Number(2)) // Number {0} Number {1} Number {2}
console.log(new Number(true) === new Number(1),new Number(0)) // false Number {0}
console.log(new Number(true) == new Number(1)) // false
// let bb: boolean = new Boolean(2)
// 不能将类型“Boolean”分配给类型“boolean”。“boolean”是基元,但“Boolean”是包装器对象。如可能首选使用“boolean”。
BOM 和 DOM 的内置对象
-
Window
-
Document
-
HTMLElement
-
DocumentFragment
-
Event
-
NodeList
const div: HTMLElement = document.getElementById('test')
const divs: NodeList = document.querySelectorAll('div')
document.addEventListener('click', (event: MouseEvent) => {
console.dir(event.target) // console.dir()可以显示一个对象所有的属性和方法。
})
const fragment: DocumentFragment = document.createDocumentFragment()