一. 类型申明
-
常见类型
string、number、booleanlet a: string = '111' let b: number = 222 let c: boolean = false // 函数参数类型,返回值类型 function sum(a: number, b: number): number { return a + b } console.log(sum(1, 2));
-
联合类型
使用 | 连接多个类型let a: string | boolean a = '111' a = false // 直接使用字面量进行声明,类似常量 let b: 10 // b= 11 报错 let c: 10 | '10' c = '10'
-
any 类型
any 表示任意类型// any 表示任意类型,一个变量设置类型为 any 后相当于对该变量关闭了 TS 的类型检测,不建议使用 // let d:any // 声明变量如果不指定类型,则 TS 解析器会自动判断变量的类型为 any (隐式的 any) let d d = 1 d = '1' d = true
-
unknown 类型
表示未知类型的值// d 是 any 隐式类型 let d d = '1' // unknown 类型 let e: unknown e = 1 e = true e = '1' let s: string // any 可以赋值给任何变量,不会报错;unknown 一个安全类型的 any,不能直接赋值给变量 // s= d 不错报 // s= e 报错
-
类型断言
告诉解析器变量的实际类型/* 语法: 变量 as 类型 <类型>变量 */ s = e as string s = <string>e
-
void 和 never 类型
// void:表示空 undefined ,以函数为例,表示没有返回值的函数 function fn1(): void { } // never:表示永远不会返回结果 function fn2(): never { throw new Error('报错了!') }
-
object 类型
对象类型// {} 用来指定对象中可以包含哪些属性 // 语法:{属性名:属性值,属性名:属性值....} // 在属性名后面加上 ?, 表示属性是可选的 let f: { name: string, age?: number } // f = { name: '11' } f = { name: '11', age: 12 } // [propName: string]: any 表示任意类型的属性 let g: { name: string, [propName: string]: any } g = { name: '11', age: 18, gender: '男' } // 设置函数结构的类型申明 // 语法:(形参:类型,形参:类型...) => 类型 let u: (a: number, b: number) => number u = function (n1: number, n2: number) { return 10 }
-
Array类型
数组类型// 语法: // 类型[] // Array<类型> // string[] 表示字符串数组 let i: string[] i = ['1', '2'] // number[] 表示数字数组 let p: number[] p = [1, 2] let y: Array<string> y = ['1']
-
元组
固定长度的数组// 语法:[类型,类型,类型] let r: [string, number] r = ['1', 2]
-
enum
枚举// 如果不指定数值,则从 0 开始 enum Gender { Male = 1, FeMale = 0 } let w: { name: string, gender: Gender } w = { name: '11', gender: Gender.Male } console.log(w.gender);
-
& 和 别名
// & 表示同时 let j: { name: string } & { age: number } j = { name: '1', age: 18 } // 类型别名 type myType = 1 | 2 | 3 let k: myType let z: myType z = 2
二. tsconfig.json
tsconfig.json 包含 TypeScript 编译的相关配置,通过更改编译配置项,我们可以让 TypeScript 编译出 ES6、ES5、node 的代码。
重要字段
files - 设置要编译的文件的名称;
include - 设置需要进行编译的文件,支持路径模式匹配;
exclude - 设置无需进行编译的文件,支持路径模式匹配;
compilerOptions - 设置与编译流程相关的选项。
compilerOptions 选项
{
"compilerOptions": {
/* 基本选项 */
"target": "es5", // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
"module": "commonjs", // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
"lib": [], // 指定要包含在编译中的库文件
"allowJs": true, // 允许编译 javascript 文件
"checkJs": true, // 报告 javascript 文件中的错误
"jsx": "preserve", // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
"declaration": true, // 生成相应的 '.d.ts' 文件
"sourceMap": true, // 生成相应的 '.map' 文件
"outFile": "./", // 将输出文件合并为一个文件
"outDir": "./", // 指定输出目录
"rootDir": "./", // 用来控制输出目录结构 --outDir.
"removeComments": true, // 删除编译后的所有的注释
"noEmit": true, // 不生成输出文件
"importHelpers": true, // 从 tslib 导入辅助工具函数
"isolatedModules": true, // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).
/* 严格的类型检查选项 */
"strict": true, // 启用所有严格类型检查选项
"noImplicitAny": true, // 在表达式和声明上有隐含的 any类型时报错
"strictNullChecks": true, // 启用严格的 null 检查
"noImplicitThis": true, // 当 this 表达式值为 any 类型的时候,生成一个错误
"alwaysStrict": true, // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
/* 额外的检查 */
"noUnusedLocals": true, // 有未使用的变量时,抛出错误
"noUnusedParameters": true, // 有未使用的参数时,抛出错误
"noImplicitReturns": true, // 并不是所有函数里的代码都有返回值时,抛出错误
"noFallthroughCasesInSwitch": true, // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)
/* 模块解析选项 */
"moduleResolution": "node", // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
"baseUrl": "./", // 用于解析非相对模块名称的基目录
"paths": {}, // 模块名到基于 baseUrl 的路径映射的列表
"rootDirs": [], // 根文件夹列表,其组合内容表示项目运行时的结构内容
"typeRoots": [], // 包含类型声明的文件列表
"types": [], // 需要包含的类型声明文件名列表
"allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。
/* Source Map Options */
"sourceRoot": "./", // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
"mapRoot": "./", // 指定调试器应该找到映射文件而不是生成文件的位置
"inlineSourceMap": true, // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
"inlineSources": true, // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
/* 其他选项 */
"experimentalDecorators": true, // 启用装饰器
"emitDecoratorMetadata": true // 为装饰器提供元数据的支持
}
}
三. ts 结合 webpack
-
新建文件夹,执行
npm init -y
-
安装依赖
npm i webpack webpack-cli typescript ts-loader -D
-
根目录下新建 webpack.config.js
const path = require('path') module.exports = { "entry": "./src/index.ts", "output": { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, "module": { "rules": [ { test: /\.ts$/, use: 'ts-loader', exclude: /node_modules/ } ] } }
-
根目录下新建 tsconfig.json
{ "compilerOptions": { "module": "ES2015", "target": "ES2015", "strict": true } }
-
在 package.json 中添加 build 命令
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack" },
四. 类
属性和方法
class Person {
// 实例属性:实例化后使用
name: string = "孙悟空"
age: number = 18
// 静态属性:可以直接通过类使用
static gender: string = 'male'
// 只读属性:无法修改
readonly height: number = 178
// 方法:分为实例方法和静态方法
sayHello() {
console.log('hello');
}
static sayHi() {
console.log('Hi');
}
}
const per = new Person()
console.log(per);
console.log(per.name);
console.log(Person.gender);
// per.height = 188
per.sayHello()
Person.sayHi()
五. 构造函数和this
constructor 被称为构造函数,会在对象创建时调用
class Person {
name: string;
age: number;
// constructor 被称为构造函数,会在对象创建时调用
constructor(name: string, age: number) {
// 在实例方法中,this 就代表当前的实例
// 在构造函数中当前对象就是当前新建的那个对象
// 可以通过 this 向新建的对象中添加属性
this.name = name
this.age = age
}
sayHello() {
// 在方法中可以通过 this 来表示当前调用方法的对象
console.log(this);
}
}
const per = new Person('孙悟空', 18)
const per2 = new Person('孙悟空2', 182)
// console.log(per);
// console.log(per2);
per2.sayHello()
六. 继承
使用继承后,子类将会拥有父类所有的属性和方法
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name
this.age = age
}
sayHello() {
console.log(this);
}
}
// 此时,Person 被称为父类,Dog 被称为子类
// 使用继承后,子类将会拥有父类所有的属性和方法
// 如果希望在子类中添加一些父类中没有的属性或方法,直接加载子类中即可
// 重写:如果在子类中添加了和父类相同的方法,则子类中的方法会覆盖父类的方法,这种方式叫
class Zs extends Person {
sayHi() {
console.log("hi");
}
}
class Ls extends Person {
sayHello() {
console.log('hello');
}
}
let zs = new Zs('zhangsan', 18)
zs.sayHello()
zs.sayHi()
let ls = new Ls('lisi', 28)
ls.sayHello()
七. super
如果在子类中写了构造函数,在子类构造函数中必须使用 super 调用父类构造函数
class Person {
name: string;
constructor(name: string) {
this.name = name
}
sayHello() {
console.log(this);
}
}
class Zs extends Person {
// 如果在子类中写了构造函数,在子类构造函数中必须使用 super 调用父类构造函数
age: number;
constructor(name: string, age: number) {
super(name)
this.age = age
}
sayHi() {
console.log("hi");
}
}
let zs = new Zs('张三', 18)
zs.sayHello()
zs.sayHi()
八. 抽象类
以 abstract 开头
// 抽象类:
// 以 abstract 开头
// 只能被继承,不能用来创建对象
abstract class Person {
name: string;
constructor(name: string) {
this.name = name
}
// 抽象方法:
// 使用 abstract 开头,没有方法体
// 只能定义在抽象类中,子类必须重写该方法
abstract sayHello(): void
}
class Zs extends Person {
sayHello() {
console.log('hello');
}
sayHi() {
console.log("hi");
}
}
let zs = new Zs('张三')
zs.sayHello()
zs.sayHi()
九. 接口
可以在定义类的时候去限制类的结构
// 接口:
// 可以在定义类的时候去限制类的结构
// 所有的属性都不能有实际的值
// 只定义对象的结构,而不考虑实际值
// 在接口中所有的方法都是抽象方法
interface Person {
name: string;
sayHello(): void
}
// 定义类时,可以使类去实现一个接口,使类满足接口的要求
class Zs implements Person {
name: string
constructor(name: string) {
this.name = name
}
sayHello() {
console.log('hello');
}
}
let zs = new Zs('张三')
zs.sayHello()
十. 属性的封装
public、private、protected
class Person {
// public 可以在任意位置访问(修改) 默认值
// private 只能在类内部访问(修改)
// protected 受保护的属性,只能在类和子类中访问(修改)
// 通过在类中添加方法使得私有属性可以被外部访问和修改
private _name: string
private _age: number
constructor(name: string, age: number) {
this._name = name
this._age = age
}
// TS 中设置 getter 和 setter,他们被叫做存取器
// getter 方法用来读取属性
// setter 方法用来设置属性
get name() {
return this._name
}
set name(value) {
this._name = value
}
}
class C {
// 可以直接将属性定义在构造函数中
constructor(public name: string, public age: number) {
}
}
let Ls = new C('lisi', 38)
console.log(Ls);
let Zs = new Person('zhangsan', 18)
Zs.name = 'lisi'
console.log(Zs.name);
十一. 泛型
在定义函数时,如果遇到类型不明确可以使用泛型
// 在定义函数时,如果遇到类型不明确可以使用泛型
function fn<T>(a: T): T {
return a
}
// 可以直接调用具有泛型的函数
let result = fn(10) // 不指定泛型,TS 自动推断
let result2 = fn<string>('hello') // 指定泛型类型
console.log(result, result2);
// 泛型可以同时指定多个
function fn2<T, K>(a: T, b: K): T {
console.log(b);
return a
}
fn2<number, string>(12, 'hello2222')
// T extends Inter 表示泛型 T 必须是 Inter 实现类(子类)
interface Inter {
length: number
}
function fn3<T extends Inter>(a: T): number {
return a.length
}
class myClass<T>{
name: T
constructor(name: T) {
this.name = name
}
}
const mc = new myClass('孙悟空')
console.log(mc);
参考链接:
https://juejin.cn/post/7018805943710253086?share_token=c4029c41-9cc7-4e39-9e2d-c57b6617d2d8#comment
https://www.bilibili.com/video/BV1Xy4y1v7S2/?p=10&spm_id_from=pageDriver&vd_source=4e82b49ed21a06688f8dfee0c73a125f