基本类型
- string、number、boolean、undefined、null
赋值时自动判定类型,无需定义
let aa = '1';
// 等同于
let aa: string = '1';
- 拓展的基础类型:any、void、never
any:任意类型,不确定类型或者类型是动态的
void:表示无任何类型,正好与 any 相反。对于变量,表示类型为 undefined 或 null;对于函数,表示函数没有返回值,或者返回 undefined
function aa(): void{
console.log('无返回')
}
never:表示永远不存在值。一般用在抛出异常的函数
function aa(): never{
throw new Error('报错')
}
unknown:表示未知类型。即写代码的时候还不清楚会得到怎样的数据类型,如服务器接口返回的数据,JSON.parse() 返回的结果等
它能被赋值为任何类型,但不能被赋值给除了 any 和 unknown 之外的其他类型,同时,不允许执行 unknown 类型变量的方法(any 可以)
let uk: unknown = 'abc';
uk = 123;
uk = true;
uk.toString(); // Error
let valAny: any = 'abc';
valAny.toString(); // 'abc'
let uk1: unknown = uk;
let uk2: any = uk;
let uk2: string = uk; // Error,只能赋值any 和 unknown类型
引用类型
- 数组类型
let arr: string[] = ['a', 'b', 'c'];
// 等同于
let arr: Array<string> = ['a', 'b', 'c'];
// 只读数据
let arrR: ReadonlyArray<string> = ['a', 'b', 'c'];
arrR[0] = 'd'; // 报错
- object: 表示类型为对象,除基本类型外的类型
函数类型
function aa(x: number, y: number): number {
return x + y;
}
aa(1, 2);
枚举 enum
// 1、默认从 0 递增赋值
enum EColor {Red, Blue, Green};
console.log(EColor["Red"] === 0); // true
console.log(EColor["Blue"] === 1); // true
// 2、手动赋值
enum EDays {
Mon = 'mon',
TUE = 'tue',
WEN = 'wen'
}
console.log(EDays["Mon"] === 0); // true
// 3、只允许输入EDays的值
function aa(day: EDays){
console.log(day) // tue
}
aa(EDays.TUE)
// 4、可循环遍历
for(let item of Object.entries(Days)){
console.log(item) // ["Mon", "mon"] ...等等
}
// 5、固定值
type name = 'tom' | 'cat';
const fullName: name = 'tom'; // 只能为'tom' | 'cat'
高级类型:联合类型、交叉类型、类型断言
- 联合类型 可取多种类型,如:
// 基本类型
let aa: string | number;
aa = '1';
aa = 1;
// 数组
let arr: number[] | string[];
arr = [1, 2, 4]
arr = ['a', 'b', 'c']
// 对象
interface IRectangle {
kind: 'rectangle';
width: number;
height?: number;
}
interface ICircle {
kind: 'circle';
radius: number;
}
type TShape = IRectangle | ICircle;
let aa: TShape = {
kind: 'circle',
radius: 10
}
console.log(aa.radius) // 10
aa = {
kind: 'rectangle',
width: 1
}
console.log(aa.width) // 1
- 交叉类型 交叉类型是将多个类型合并为一个类型
interface Person {
name: string
age: number
}
interface Student {
school: string
}
type StudentInfo = Person & Student
const stu: StudentInfo = {
name: 'Tom',
age: 23,
school: 'Oxford',
}
- 类型断言
- as 操作符
interface Cat {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
// 对于一些不知道参数类型,可以断言为any, 或者参数为多个类型时,断言为某个类型
function isFish(animal: Cat | Fish) {
if (typeof (animal as Fish).swim ==='function') { //此处用animal.swim报错
return true;
}
return false;
}
- !非空断言操作符
// 忽略 undefined 和 null 类型
interface IObj {b:1}
const a: IObj | undefined = undefined;
const obj: IObj = a!;
const b: number = a!.b;
// 调用函数时忽略 undefined 类型
type NumGenerator = () => number;
function myFunc(numGenerator?: NumGenerator) { // 等同:numGenerator: NumGenerator | undefined
// Cannot invoke an object which is possibly 'undefined'.(2722)
const num1 = numGenerator(); // Error
const num2 = numGenerator!(); //OK
}
接口
接口是描述值的结构,属性如下:
- 任意属性(字符串索引类型)、可选属性 [propName:string]
interface IPerson {
readonly phone: number; // 只读属性
name: string; // 固定属性,必要
age?: number; // 可选属性,非必要
[propName: string]: string | number | string[] | undefined; // 包含可选属性功能age?需要undefined
}
let tom: IPerson = {
name: 'Tom',
gender: 'male', // 任意一个
phone: 188888888
};
tom.phone = 19999999 // Cannot assign to 'phone' because it is a read-only property.
2.type(类型别名)和interface(接口)区别
interface 和 type 两个关键字的含义和功能都非常的接近
- interface:
- 同名的 interface 自动合并
- 只能表示 object、class、function 类型
- type:
- 不仅仅能够表示 object、class、function
- 不能重名(自然不存在同名聚合了),type支持复杂的类型操作
- 与 interface 不同,type 还可以用来标书其他的类型,比如基本数据类型、元素、并集等
type TName = string;
type TNameResolver = () => string;
type TNameOrResolver = Name | NameResolver;
3.函数
// 函数声明方式1
type LongHand = {
(a: number): number;
};
// 函数声明方式2
type ShortHand = (a: number) => number;
// 以上方式相当于
function person(a: number): number { return a }
const person: LongHand = (a) => { return a} // 这里有类型推断,省略了(a: number): number =>
4.类与继承
// 接口可以继承多个接口,合并所有接口的声明字段
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = <Square> {};
square.color = 'red'
square.sideLength = 10;
// 接口继承类,合并类的成员和结构
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
// 以react为例:
// class类型
export default class VisibleTodoList extends React.Component<{a:number}>
// hook类型
export default const EditPlanbook: React.FC<{a: number}>{}
声明合并
声明同名的函数会合并,声明同名的接口会合并,声明同名的类会合并
声明文件
声明文件须以 .d.ts 为后缀
- 声明模块:
// 转dayjs为moment
declare module 'moment' {
import dayjs, { Dayjs } from 'dayjs';
export default dayjs;
}
import moment from 'moment';
// 声明新模块,使m有fn函数
declare module "SomeModule" {
export function fn(): string;
}
import * as m from "SomeModule";
m.fn()
- 全局模块:
1.定义全局默认类型
declare global {
// 给全局String类型加prependHello方法
interface String {
prependHello(): string;
}
// 给全局window类型加projectConf、projectMainConf、eventBus属性
interface Window {
projectConf: Record<string, any>;
projectMainConf: Record<string, any>;
eventBus?: any;
}
}
// 注意: 修改"全局声明"必须在模块内部, 所以至少要有 export{}字样
// 不然会报错❌: 全局范围的扩大仅可直接嵌套在外部模块中或环境模块声明中
export {};
'bar'.prependHello();
2.declare全局自定义类型
// 通用接口返回类型,.d.ts默认全局
declare interface ApiResp<T> {
data: T;
code: number;
msg: string;
message: string;
}
3.其余的还有: declare namespace 声明(含有子属性的)全局对象
泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray<string>(3, 'x'); // ['x', 'x', 'x']
createArray(3, 'x'); // ['x', 'x', 'x'],'x'会自动被推断为string
在函数名后添加了 ,其中 T 用来指代任意输入的类型,在后面的输入 value: T 和输出 Array 中即可使用了
- response内容的定义用泛型
declare interface ApiResp<T> {
data: T;
code: number;
message: string;
}
type TPlanbookRes = {
list: string[];
totalCount: number;
}
interface SpeechMgmtProps {
getPlanbookList: () => Promise<ApiResp<TPlanbookRes>>;
}
- 请求方式,如:axios
get方法:
interface AxiosInstance{
get<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
}
axios.get<TPlanbookRes>(`/app/rooms/uniqs/url`);
泛型工具类型-常用的
- Record:以 typeof 格式快速创建一个类型,此类型包含一组指定的属性且都是必填。
type Coord = Record<'x' | 'y', number>;
// 等同于
type Coord = {
x: number;
y: number;
}
- Partial: 将类型定义的所有属性都修改为可选。
type Coord = Partial<Record<'x' | 'y', number>>;
// 等同于
type Coord = {
x?: number;
y?: number;
}
- Pick:从类型定义的属性中,选取指定一组属性,返回一个新的类型定义。
type Coord = Record<'x' | 'y', number>;
type CoordX = Pick<Coord, 'x'>;
// 等用于
type CoordX = {
x: number;
}
- Omit:从类型定义的属性中,排除某个属性
type Omit<T, K> 等于 Pick<T, Exclude<keyof T, K>>
// 使用:
type Foo = Omit<{name: string, age: number}, 'name'>
let aa: Foo = {age: 1} // 已无name属性
编译上下文
- 如果一个目录下存在一个tsconfig.json文件,那么它意味着这个目录是TypeScript项目的根目录。 tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项
- 使用"files"属性,指定需要编译的文件
{
"compilerOptions": {},
"files": [
"./some/file.ts"
]
}
- 使用 include 和 exclude 选项来指定需要包含的文件和排除的文件
{
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
-
可以通过 compilerOptions 来定制你的编译选项
如果"files"和"include"都没有被指定,编译器默认包含当前目录和子目录下所有的TypeScript文件,可使用compilerOptions来定制你的编译选项
1.@types:默认所有可见的"@types"包会在编译过程中被包含进来, node_modules/@types文件夹下以及它们子文件夹下的所有包都是可见的。
2.ypeRoots:如果指定了typeRoots,只有typeRoots下面的包才会被包含进来。 如:
{
"compilerOptions": {
"typeRoots" : ["./typings"]
}
}
这个配置文件会包含所有./typings下面的包,而不包含./node_modules/@types里面的包
3.types:如果指定了types,只有被列出来的包才会被包含进来。同时可指定"types": []来禁用自动引入@types包
{
"compilerOptions": {
"types" : ["node", "lodash", "express"]
}
}
这个配置文件将仅会包含 ./node_modules/@types/node,./node_modules/@types/lodash和./node_modules/@types/express。/@types/。 node_modules/@types/*里面的其它包不会被引入进来。
- 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 // 为装饰器提供元数据的支持
}
}
PS: 常用第三方库-antd的ts记录
- Input:
- e.currentTarget.value
onChange = (e: React.FormEvent<HTMLInputElement>) => {
const newValue = e.currentTarget.value;
}
- e.target.value
onChange = (e: React.ChangeEvent<HTMLInputElement>)=> {
const newValue = e.target.value;
}
- Radio:
import { RadioChangeEvent } from 'antd/lib/radio';
onRadioChange = (e: RadioChangeEvent) => {}
- select:
import { SelectValue } from 'antd/lib/select';
4.RangePicker:
import { RangePickerProps } from 'antd/es/date-picker/generatePicker';
onChangeTime = (dates: RangePickerValue, dateStrings: string[])
import moment from 'moment';
type RangePickerValue = RangePickerProps<moment.Moment>['value'];
- pagination:
import { TablePaginationConfig } from 'antd/lib/table';
babel转译ts,在线编译ts
- ts在线转js&ts在线编译在线编译