一、Typescript手册
1.1 基础类型
1.1 静态类型
// 数组类型
let person: string[] = ['zhangsan', 'lisi', 'wangwu', 'zhaoliu']
// 对象类型
let person1: {
name: string
age: number
} = {
name: 'zhangsan',
age: 18,
}
// 类类型
class Person {}
let person2: Person = new Person()
// 函数类型
const person3: () => string
= () => 'zhangsan'
1.2 类型推断
// 数组类型推断
let a = ['zhangsan', 'lisi', 'wangwu']
// 自动推导
let c = 1
// 对象自动推导
let person4 = {
name: 'zhangsan',
age: 18,
}
1.3 函数参数
// 函数类型
const demo1 = (one: number, two: number): number => one + two
const b = demo1(1, 2)
// 函数参数为对象类型
const demo2 = ({ one, two }: { one: number; two: number }) => one + two
demo2({ one: 1, two: 2 })
1.4 数组类型注解
const numberArr: number[] = [1, 2, 3, 4]
const stringArr: string[] = ['zhangsan', 'lisi']
const anyArr = ['123', 1, { name: 'zhangsan', age: 18 }]
// 类型是数组中嵌套对象
// 1、第一种写法
const persons: { name: string; age: number }[] = [{ name: 'zhangsan', age: 18 }]
// 2、第二种写法
class Persons {
name: string
age: number
}
const persons1: Persons[] = [{ name: 'zhangsan', age: 18 }]
// 3、第三种写法
type male = { name: string; age: number }
const persons2: male[] = [{ name: 'zhangsan', age: 18 }]
1.5 元组
// 字符串和数字类型数组
const person5: (string | number)[] = ['zhangsan', 18]
// 元组 (严谨:必须按照类型顺序填写对应的数据)
const person6: [string, number] = ['zhangsan', 18]
// 元组数组
const person7: [string, number][] = [
['zhangsan', 18],
['lisi', 18],
['wangwu', 18],
]
1.2 变量声明
1.3 接口
1.3.1 可选属性
interface SquareConfig {
color?: string
width?: number
}
function createSquare(config: SquareConfig) {
let newSquare = { color: "white", area: 100 };
if (config.color) {
newSquare.color = config.color;
}
if (config.width) {
newSquare.area = config.width * config.width;
}
return newSquare
}
let mySquare = createSquare({color: "black"});
console.log(mySquare);
1.3.2 只读属性
interface Point {
readonly x: number;
readonly y: number
}
let p1: Point = { x: 1, y: 2 };
p1.x = 10; // 报错
1.3.3 额外的属性检查
1、类型断言
interface SquareConfig {
color?: string;
width?: number;
}
// colour 不属于 SquareConfig,会报错, 可以使用类型断言
let mySquare = createSquare({ opacity: 0.5, width: 100 } as SquareConfig);
2、添加字符串索引签名
interface SquareConfig {
color?: string;
width?: number;
[propName: string]: any;
}
let mySquare = createSquare({ opacity: 0.5, width: 100 });
1.3.4 可索引的类型
任意个数键为 key, 值为value的属性
// key为 数值类型, value 为字符串类型
interface StringArray {
[index: number]: string
}
let strArr1: StringArray = { 0: "Bob", 1: "Fred" }
let strArr2: StringArray = ["Bob", "Fred"]
// key为 字符串类型, value为字符串类型
interface Person {
[ propName: string ] : string
}
let p1:Person = {
name: "zhangsan",
height: "1.8",
sex: "nan"
}
1.3.5 函数类型
interface Iter {
func: (a: number, b: number) => void
}
const a: Iter = {
func: (a: number, b: number) => {
console.log(a, b);
}
}
// 测试
a.func("wdq","dwq");
1.4 类
7.1 类的基本使用
class person {
content = 'hello world'
sayHello() {
return this.content
}
}
class persons extends person {
sayHello() {
// super指向了父类
return super.sayHello() + '你好'
}
sayHi() {
return 'hi world'
}
}
// 测试
const people = new persons()
console.log('people.sayHi(): ', people.sayHi())
console.log('people.sayHello(): ', people.sayHello())
7.2 类的访问类型
// public 公共的属性或方法
// protected 受保护的的属性或方法 ,继承的类可以访问到
// private 只能在类的内部进行使用
class Person {
public content: string = 'hello world'
protected sayHello() {
return this.content
}
}
class Persons extends Person {
sayHi() {
return 'hi world'
}
}
// 测试
const people2 = new Persons()
people2.content = 'zhangsan'
console.log('people2.sayHi(): ', people2.sayHi())
7.3 类的构造类型
class Person2 {
constructor(public name: string) {}
}
class Persons2 extends Person2 {
constructor(public age: number) {
super('zhangsan')
}
}
// 测试
const people3 = new Persons2(18)
console.log(people3.age)
console.log(people3.name)
7.4 getter和setter
class PerSon {
constructor(public _name: string) {}
get name() {
return this._name
}
set name(_name: string) {
this._name = 'zhangsan'
}
}
// 测试
const zhangsan = new PerSon('lisi')
console.log(zhangsan)
7.5 static
class PerSon1 {
static sayHello() {
return 'hello world'
}
}
// 测试
console.log(PerSon1.sayHello())
7.6 只读属性和抽样类
// 抽象类
abstract class Girl {
abstract run()
}
class demo extends Girl {
run() {
return '跑'
}
}
// 只读属性
class demo1 {
public readonly _name: string
constructor(name: string) {
this._name = name
}
}
// 测试
const test = new demo1('zhangsan')
console.log(test._name)
7.7 构造签名
// new (x: number, y: number) 被称为构造签名
interface Point {
new(x: number, y: number): Point; // 构造函数的参数类型
x: number;
y: number;
}
class Point2D implements Point {
readonly x: number;
readonly y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
1.5 函数
1.5.1 函数返回值是元组
1.5.2 返回多种函数类型
interface FactoryType {
(a?: any, b?: string): string;
(a?: number, b?: string, c?: number): string;
}
function factory(): FactoryType {
return function (a?: number, b?: string, c?: number) {
return "fqwjklhfklqw";
};
}
1.6 泛型
1.6.1 函数泛型
1.6.1.1 普通函数
function createArr<T>(length: number, value: T): Array<T> {
let arr = []
for (var i = 0; i < length; i++) {
arr[i] = value
}
return arr
}
1.6.1.2 箭头函数
const createArr = <T>(length: number, value: T): Array<T> => {
let arr = []
for (var i = 0; i < length; i++) {
arr[i] = value
}
return arr
}
// 在调用的时候指定T为string类型
const stringArr: Array<string> = createArr<string>(10, '2')
// 如果在调用得时候也不指定类型那么会自动推到
// 因为1是number所以推出T为number,那么返回值也是number数组,如果使用其他类型数组接收返回值,会报错
const numberArr: Array<number> = createArr(3, 1)
1.6.2 泛型类
1.7 枚举
// 使用时 BussinessStatus.CODE_SUCCESS
export enum BussinessStatus {
CODE_SUCCESS = 200,
WARN_TIP = 400,
SYSTEM_EXCEPTION = 500,
LOGIN_FAILURE = 600,
LOGIN_FAILED = 700,
}
1.8 类型推论
1.8.1 自动推断
没有指出具体类型,ts会自动推断类型
let x = 1; // 推断为number
1.8.2 最佳通用类型
// number | null
let x = [0, 1, null];
// 类型推断的结果为联合数组类型
let zoo = [new Rhino(), new Elephant(), new Snake()]; // (Rhino | Elephant | Snake)[]
// 当候选类型不能使用的时候我们需要明确的指出类型
let zoo: Animal[] = [new Rhino(), new Elephant(), new Snake()];
1.8.3 上下文类型
TypeScript类型检查器使用
Window.onmousedown函数的类型来推断右边函数表达式的类型。 因此,就能推断出mouseEvent参数的类型了。
window.onmousedown = function(mouseEvent) {
console.log(mouseEvent.button); //<- Error
};
如果上下文类型表达式包含了明确的类型信息,上下文的类型被忽略。 重写上面的例子:
window.onmousedown = function(mouseEvent: any) {
console.log(mouseEvent.button); //<- Now, no error is given
};
1.9 类型兼容性
1.10 高级类型
1.10.1 交叉类型
1.10.2 联合类型
1.10.3 类型保护与区分类型
1.10.4 类型别名
typeof 可以获取一个具体值的类型
1.10.4.1 typeof与函数结合使用
function add(a: number, b: number): number {
return a + b;
};
type t1 = typeof add;
let test: t1 = function (a: number, b: number): number {
return 1
};
1.10.4.2 typeof与类结合使用
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
};
// 这里 typeof Point 等价于 new (x: number, y: number) => number;
function getInstance(PointClass: typeof Point, x: number, y: number) {
return new PointClass(x, y);
}
function getInstance2(PointClass: Point, x: number, y: number) {
return new PointClass(x, y); // 报错 此表达式不可构造。类型 "Ponit" 没有构造签名。
}
1.10.4.3 typeof和function结合使用
function run(maybeArgv?: Array<string>, project?: Config.Path): Promise<void>;
const default = {
run: typeof run; // 等价于 (maybeArgv?: Array<string>, project?: Config.Path) => Promise<void>;
}
1.11 三斜线指令
三斜线指令是一种特殊的注释语法,用于在TypeScript文件中引入外部模块或库的声明文件。
///
其中,
path/to/file.d.ts是声明文件的路径。通过使用三斜线指令,我们可以告诉编译器在编译过程中引入指定的声明文件,以便在代码中使用相关的类型定义和接口。需要注意的是,从TypeScript 2.0版本开始,推荐使用ES6模块语法(
import和export)来引入外部模块,而不是使用三斜线指令。三斜线指令主要用于旧版的TypeScript项目或需要与其他工具(如JSDoc)进行集成的情况下使用。
例如:
// 表明这个文件使用@types/node/index.d.ts里面声明的名字
/// <reference types="node">;
1.12 关键字
1.12.1 keyof关键字
获取类型中所有键值 作为 类型
type Person = {
name: string,
age: number,
gender: string
}
type PersonKeys = keyof Person; // 类型为 "name" | "age" | "gender";
let test1: PersonKeys = "name";
let test2: PersonKeys = "age";
let test3: PersonKeys = "sex";
1.12.2 infer关键字
infer关键字用于提取类型中的信息。当我们定义一个泛型类型或条件类型时,infer用于提取类型变量的实际类型。对于条件类型,
infer通常与extends关键字一起使用
// Str 类型是以空格后跟其他字符串开始,Rest类型为Hello World
// 例如: TrimLeft<" hello">, 条件Str entends ` ${infer Rest}`的结果将是Rest类型为 "hello";
type TrimLeft<Str extends string> = Str extends ` ${infer Rest}` ? TrimLeft<Rest> : Str;
type TrimRight<Str extends string> = Str extends `${infer Rest} ` ? TrimRight<Rest> : Str;
type Trim<Str extends string> = TrimLeft<TrimRight<Str>>;
type T2 = Trim<' Hello World '>;
const str: T2 = "Hello World"
console.log(str);
1.13 any、unknown、never和void
any:任意类型的变量
unknown: 表示未知类型 unknown与any类似 但使用前必须进行断言或守卫
never:永不存在的值的类型
void: 无任何类型,没有类型 用于函数时,never表示函数用于执行不到返回值那一步(抛出异常或死循环)的返回值类型 即永不存在的值的类型。 而void则表示没有返回值,不返回或返回undefined
1.13.2 unknow
不允许直接使用 unknow 变量,需要将该变量强制转换为已知类型或收窄其类型
const x: unknow = {
a: "a-value",
b: "b-value"
}
(x as {a: string, b: string}).a;
1.14 模块添加声明
添加模块声明之后需要自己编写类型模块,否测找不到对应类型提示
第三方类库没有 *.d.ts 文件,需要在项目跟目录下添加 types/index.d.ts文件,在文件中声明模块
1.15 常用泛型类型
1.15.1 获取函数返回值
function test() {
return "string";
}
type ReturnType1 = ReturnType<typeof test>;
1.15.2
interface MainType {
name: string,
age: number
}
type NestedType = MainType & {
isDeveloper: boolean
}
type Preffity<T> = {
[K in keyof T]: T[K]
} & {}
type idk = Preffity<NestedType>
1.15.3 可选参数,必填参数
interface Todo {
title: string,
description: string
}
const updateTodo = (todo: Todo, filedsToUpdate: Partial<Todo>) => {
return { ...todo, filedsToUpdate };
}
const initTodo: Todo = {
title: "stirng",
description: "string"
}
updateTodo(initTodo, {})
// 大体实现
// Partial 将接口类型参数变为可选
// 大体实现
// type Partial1<T> = {
// [K in keyof T]?: T[K]
// }
// Required 将接口类型参数变为必填
// type Required1<T> = {
// [K in keyof T]-?: T[K];
// };
1.15.4 省略多个属性
interface Test {
name: string,
age: number,
createAt: Date
}
const t: Omit<Test, "name" | "age" | "createAt"> = {}
type aaa = {
kind: "circle",
name: string
} | {
kind: "square",
x: number
}
type b = Exclude<aaa, { kind: "circle" } | { kind: "squre" }>
1.15.5 定义对象
const map: Record<string, string> = {};
// Record类型源码
type Record<K extends keyof any, T> = {
[P in K]: T;
};
1.15.6 函数第二个参数根据第一个参数类型变化
interface Attributes {
a: string;
b: string;
c: CType
}
interface CType {
name: string;
age: number
}
function test1<K extends keyof Attributes>(param1: K, param2: Attributes[K]) {
const _this: Attributes = {
a: "1",
b: "2",
c: {
name: "string",
age: 1
}
};
_this[param1] = param2;
return _this;
}
// 测试
console.log(test1("c", { name: "1", age: 1 }));
二、Typescript配置
2.1 compilerOptions配置
{
"compilerOptions": {
/* 基本选项 */
"target": "es5", // 指定 ECMAScript 目标版本: 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'esnext'
"module": "commonjs", // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' ,'ES6','es2022',or 'esnext'
"lib": [], // 指定要包含在编译中的库文件,也就是库的声明文件用于代码提示,
//当你用三方库(例如polyfills)实现了高版本js的部分写法,但又不是全部(所以不能直接指定target为高版本)
"allowJs": true, // 允许编译 javascript 文件,在js文件中可以有d.ts/ts文件的类型提示
"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 语句贯穿)
"skipLibCheck": true, // 跳过所有声明文件的类型检查
"skipDefaultLibCheck": true, //只跳过默认声明文件的类型检查,也就是忽略检查带有/// <reference no-default-lib=“true”/>的文件。
/* 模块解析选项 */
"moduleResolution": "node", // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
"baseUrl": "./", // 用于解析非相对模块名称的基目录
"paths": {}, // 模块名到基于 baseUrl 的路径映射的列表
"rootDirs": [], // 根文件夹列表,其组合内容表示项目运行时的结构内容
"typeRoots": [], // 指定类型文件包所在的文件夹(文件夹下有多个包),未设置默认@types,
// 与types不同的是,typeRoots指定包所在的文件夹,types指定单个包,
// 只支持使用相对路径(./xxx/xxx)引用,文件夹下存在单文件无效,仅支持包。
// 包也是一个文件夹,包根目录有设置过types选项的package.json文件,或index.ts/index.d.ts文件
"types": [], // 需要包含的类型声明文件,未设置默认typeRoots指定文件夹下的所有包,设置后则仅按指定的包。
// 写法(xxx或xxx/xxx)优先在typeRoots 指定的包集合中下查找指定的包,如果没有就查找node_modules下的包,
// 如果设置了typeRoots,但是并未指定@types,那在最后还会查找一次@types。
// 写法(./xxx/xxx)相对tsc onfig.json的路径查找包,
//优先级 名称.d.ts > 名称/package.json的types设置> 名称/index.d.ts
"allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。
/* Source Map Options */
"sourceRoot": "./", // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
"mapRoot": "./", // 指定调试器应该找到映射文件而不是生成文件的位置
"inlineSourceMap": true, // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
"inlineSources": true, // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
/* 其他选项 */
"experimentalDecorators": true, // 启用装饰器
"emitDecoratorMetadata": true // 为装饰器提供元数据的支持
}
}