typeScript
2024-05-18 18:30:32
浏览量: 1010
概述
- 安装:npm install -g typescript
- 查看版本:
- tsc -v
- 把ts文件编译为js:
- tsc xxx.ts
- 初始化规则配置文件:
- tsc --init
- 会生成tsconfig.json文件
- 基本数据类型
- boolean string number null undefined
- 类型检测 typeof
- 类型推断:当声明并初始化变量时,如果不指定类型,编译器会根据初始值进行类型推导
const boo:boolean = true;
const str:string = 'aa';
const num:number = 10;
const n:null = null;
const un:undefined = undefined;
const an:any = '';//任意类型
const unk:unknown = '';//未知类型
//数组
const arr:number[] = [1,2,3];
const arr2:Array<number> = [1,2];
//元组-指定数组中类型的顺序
const person:[string,number] = ['name', 18];
//枚举
enum color = {red, black, white};//0 1 2
// enum color = {red, black = 5, white};//0 5 6
//空类型
function fn():void{}
//永不发生时的类型描述
function fn():never{}
//类型断言
let x:unknown;
const leng:number = (x as string).length;
// const leng:number = (<string>x).length;//jsx中不支持这种写法
//联合类型
let numStr:number|string = 1;
// 接口
interface IPerson {
name:string
age:number
num?:number//可选属性
readonly id:number//只读属性,只能初始化数据,不能修改
fn: (a:number) => void//函数属性
}
//索引类型接口
interface Ip2 {
[key:number]:any
}
interface Ip2 {
[index:number]:string//数字索引类型
}
const arr: Ip2 = ['a','b','c'];
//函数类型
interface IFn {
[a:number,b:number]: boolean
}
const fn: IFn = (a:number, b:number) => {
return a > b;
}
//描述类的类型
interface IPerson {
name:string
age:number
say:()=>void
}
class Person implements Iperson {
name:string
age:number
constructor(name:string,age:number){
this.name = name
this.age = age
}
say(){}
}
类的权限管理-修饰符
- public 公共的,未声明权限的成员默认是public,类实例可以访问
- private 私有的 只能在类中被访问
- protected 受保护的 类以及子类中可以被访
- readonly 只读的
//public特殊用法
class Test2 {
constructor(public name, public fn){//相当于 this.name=name;this.fn=fn
}
}
函数
- 可选参数
- 剩余参数
- 函数重载
//函数重载
function fn(str:string):string;
function fn(num:number):number;
function fn(param:string|number):string|number {
console.log(param)
};
fn('aa')
fn(10)
//类型守卫
class A{
run(){}
}
class B{}
function test(p: A | B): p is A{
if('run' in p){//in 关键字用于判断对象中是否有某一个成员
p.run()
}
return p instanceof A;
}
接口的继承
- 接口可以多继承
interface IA {}
interface IB {}
interface IC extends IA,IB {}
class CA implements Ic {}
//接口继承类,一个接口继承一个类后,会继承类中所有的成员,单不会去实现,需要接口的实现类去实现所有功能
class CB {}
interface ID extends CB {}
class CC extends CB implements ID {}
泛型
- 泛型也相当于占位符类型,或者类型变量
- 解决类型丢失的问题
- 提供代码的复用性和灵活度
- 泛型约束
- 关键字 extends
- 约束对泛型传入的类型必须具有某些属性
- 泛型new
- 使用 new()=> 类 ,来规定传入一个类作为参数
//函数中使用泛型
function fn<T,K>(a: T, b: K): [T, K]{
return [a, b];
}
const res = fn<string>('aa');
const res = fn<number>(10);
//接口中使用泛型
interface IA<T, K> {
name: T,
age: K
}
const obj:IA<string, number> = {
name: 'a', age: 18
}
//在类中使用泛型
class CA<T> {
private data: T[] = []
add(item: T){
this.data.push(item)
}
getDataItem(index:number):T {
return this.data[index];
}
}
const obj = new CA<string>();
obj.add('aa')
//泛型约束
interface IB {
length: number
}
function fn2<T extends IB>(a: T): T {
console.log(a.length);
return a;
}
fn2("aa");//类型推断后->fn2<string>("aa") 正确,因为字符串有length属性
// fn2<number>(10);//错误,因为数字有length属性
//泛型重载,有多个重载时,在类型匹配时会从上往下按顺序匹配,只要匹配成功就不再匹配后面的类型
function fn3<T>(data: T): Array<T>;//01
function fn3<T>(data: Array<T>): Array<T>;//02
function fn3(data: any){
if(Array.isArray(data)){
return data;
}
return [data];
}
// const res = fn3(['a','b']); 这如不指定泛型具体类型,根据类型推断得到的会是个二维数组的类型string[][],因为先识别的是01重载函数
const res = fn3<string>(['a','b']);//指定类型后,会走02重载函数,返回类型为string[]
const res = fn3<number>(10);
//泛型的多种写法
const fn4: <T>(data: T) => T = (data)=>{return data}
const fn5: {<T>(data: T): T} = (data)=>{return data}
interface IC<T> { (data: T): T };
const fn6:IC<string> = (data)=>{return data}
//泛型new
const create = <T>(c:new()=>T):T=>{//参数必须是类
return new c()
}
interface ID {}
class CB implements ID {}
// const iobj = create<ID>(CB);
const iobj = create(CB);//根据类型推断,可以简写
类型别名
- 关键字:type
- type 和 interface 的区别
- interface 相当于自定义创建了新的类型;type是给已有的类型其别名
- 可以定义两个同名的interface编译器会自动合并其属性;而type不允许定义重名的类型
- type可以描述基本数据类型;而interface主要用于引用类型(如:对象)的描述
- interface可以通过extends继承;而type没有继承,但可以定义联合类型和扩展类型
//类型别名不能自己赋给自己,会造成循环引用的问题
// type Foo = Foo//报错
//在3.6版本后支持定义Tree类型、递归类型
type Tree<T> = {
value: T,
next?: Tree<T>//这里必须是可选属性,否则就变成了无限递归
}
const obj:Tree<number> = {
value: 1,
next: {
value: 2
}
}
//联合类型
type Ta = string | number
//扩展类型
type Tb = { name:string }
type Tc = { age:number }
type Td = Tb & Tc
高级用法
- 关键字 keyof 获取指定类型中所有的属性,并推断出联合类型
- keyof只能修饰类型,不能修饰具体的变量/对象
//联合类型
type T1 = string | number
type T2 = 'a' | 'b' | 'c'//one of
type T3 = 'b' | 'c' | 'd'
type T4 = T2 | T3//a b c d
//keyof
interface I1 = { a: number, b: number }
type T5 = keyof I1;//相当于 type T5 = 'a' | 'b'
const obj = {name:'a',age:12}
type T6 = keyof typeof obj;//name age
function getValue<U, UK extends keyof U>(obj: U, key: UK){
return obj[key]
}
function getValue<U, UK extends keyof U>(obj: U, keys: Array<UK>): U[UK][]{
return keys.map(k => obj[k]);
}
- 关键字 in 把一个已知属性绑定到新创建的类型中
type T1 = 'a' | 'b'
type T2 = {
[key in T1]: string
}
//将一个类型中的属性转换成只读属性
type Tobj = { name:string, age:number, sex?:number }
type TreadonlyObj<T> = {
readonly [key in keyof T]: T[key]
}
type Tobj2 = TreadonlyObj<Tobj>;//Tobj2中的属性就全变成了只读属性
//把可选属性变成必选属性
type Trequired<T> = {
[key in keyof T]-?: T[key]//-? 表示去掉?,变成必选属性
}
//筛选出指定的属性
type Tpick<T, K extends keyof T> = {
[p in K]: T[p]
}
type Tobj3 = Tpick<Tobj, 'name'|'age'>;//type Tobj3 = {name:string, age:number}
- 条件类型
- 关键字 extends 判断是否相等
type E<A, B> = A extends B ? A : B;
type TisArray<T> = T extends any[] ? true : false;
type TypeName<T> = T extends string ? 'string' :
T extends number ? 'number' :
T extends boolean ? 'boolean' :
T extends undefined ? 'undefined' :
T extends Function ? 'Function' :
'object';
//分布式条件类型 - 剔除掉不需要的类型
type Tdiff<T, K> = T extends K ? never : T;
type Td = Tdiff<'a'|'b':'c', 'a'|'d'>;
//Tdiff<'a', 'a'|'d'> Tdiff<'b', 'a'|'d'> Tdiff<'c', 'a'|'d'>
//never | 'b' | 'c'
type TdiffNullUndefined<T> = Tdiff<T, null|undefined>;
type T1 = TdiffNullUndefined<string|number|null|undefined>;//string|number
- infer
- 可以通过推断代码的类型信息,为开发者提供更加智能的代码提示和自动补全功能
- 内置工具 ReturnType 中就使用了infer
//自己实现ReturnType
type TmyReturnType<T extends Function> = T extends (...args: any) => infer R ? R : never;
- 类型模板字符串
- 可以做一些类似正则表达式的匹配
type Tinfo<T extends string, K extends number> = `${T} - ${K}`;
const info:Tinfor<'aa', 10> = 'aa - 10';
type Tuid = `${string}-${string}-${string}-${string}-${string}`;
function fn(uid:Tuid){}
fn('aa-bb-cc-dd-ee');
//示例:限制参数必须是URL格式的
type TURL<P extends string, D extends string> = `${P}://${D}`;
type TvaildUrl<UL extends string> = UL extends TURL<'http'|'https', `${string}.${string}`> ? UL : never;
function testFn<T extends string>(url: TvaildUrl<T>){}
testFn('http://xxx.com')
testFn('https://xxx.com')
// testFn('ftp://xxx.com')//报错
ts内置的泛型工具
- Partial
- 将一个对象类型中的所有属性变为可选属性
- Required
- 转必选属性
- Readonly
- 转只读属性
- Pick<T,K extends keyof T>
- 筛选出指定的属性
- Record<K extends keyof any, T>
- 定义一个类型,所有属性的类型都为T
- Exclude<T,U>
- 从T中去掉所有能够赋值给U的属性,然后剩下的属性构成一个新的类型
- Extract<T,U>
- 提取T中所有能够赋值给U的属性,将这些属性构成一个新的类型
- Omit<T, Ks extends keyof any>
- 从T中选取所有的属性值,然后移除属性名在Ks中的属性值
- 本质上是Pick的反向操作,排除掉Ks
- ReturnType
- 获取函数返回值的类型
// 获取构造函数函数类型的返回类型
class ClassA {}
type ta = InstanceType<typeof ClassA>
// 自定义泛型工具-定义变量的取值 只能是对象中某个属性的值
const obj = {
a: 'aa', b: 'bb'
} as const;//必须const 类型断言,指定对象为静态对象,
// type TvalueType = typeof obj[ keyof typeof obj ]
type Tvalues<T> = T[ keyof T ]
const name:Tvalues<typeof obj> = 'aa'//这里的name只能取obj的属性值,即aa或bb
装饰器
- 使用装饰器后,在编译时需要指定target,否则可能不生效
- tsc xxx --target es5 --experimentalDecorators --emitDecoratorMetadata
- 类装饰器
- 为现有的类添加属性和方法
// function decorators(value:Function, context:ClassDecoratorContext){
// // value 就是被修饰的类
// value.prototype.toString = function(){//在原型上添加成员
// console.log(this.name, this.age)//装饰器中可以访问类的this
// }
// }
type DcConstructer = { new(...args, any[]):any }
function decorators<T extends DcConstructer>(value:T, context:ClassDecoratorContext){
return class extends value {//返回一个匿名类
toString(){
console.log(this.name, this.age)
}
}
}
@decorators
class Test {
name: 'aa',
age: 18
}
//第二种写法
type DcConstructer2 = { new(...args, any[]):any }
function decorators2(){
return function<T extends DcConstructer>(value:T){
return class extends value {
sex: 1
}
}
}
const TestClass2 = decorators2()(
class {
name: 'aa',
age: 18
}
)
const tcobj = new TestClass2()
console.log(tcobj.sex)
- 方法装饰器
- 拦截函数,对函数进行修改和扩展
function inject(originalMethod:Function, context:ClassMethodDecoratorContext){
return function(this:any, ...args:any[]){
console.log('before')
originalMethod.apply(this, args)
console.log('after')
}
}
function inject2(originalMethod:Function, context:ClassMethodDecoratorContext){
return function(this:any, ...args:any[]){
console.log('before-2')
originalMethod.apply(this, args)
console.log('after-2')
}
}
class Test {
@inject
@inject2
testFn(){
console.log('test-fn')
}
}
new Test().testFn()//before before-2 test-fn after-2 after
//带参数的装饰器
function log(message:string){
return function (originalMethod:Function, context:ClassMethodDecoratorContext){
return function(this:any, ...args:any[]){
console.log(message)
originalMethod.apply(this, args)
}
}
}
class Test2 {
@log('aa')
testFn(){}
}
/**
* 最新实验性语法,有三个参数
* function fnDecorator(target:Object, propertyKey:string|symbol,descriptor:PropertyDescriptor){}
*/
- 属性装饰器
- 要么不返回,要么返回一个函数
function fieldDecorator(value:undefined, context:ClassFieldDecoratorContext){
return function(initValue:any){
return initValue + 'haha'
}
}
class Test {
@fieldDecorator
name = 'aa'
}
/**
* 最新实验性语法
* function fieldDecorator(target:Object, key:string ){}
*/
- 访问装饰器
- 返回一个函数,取代原来的取值
function lazy(value:Function, context:ClassGetterDecoratorContext){
if(context.kind === 'getter'){
return function(){
const res = value.call(this);
Object.defineProperty(this, context.name, {
value: res,
writable: false
})
return res;
}
}
}
class Test {
@lazy
get value(){
return 'aa'
}
}
/**
* 最新实验性语法
* function fieldDecorator(target:Object, name:string|symbol,descriptor:PropertyDescriptor){}
*/
- 存取器装饰器
- 加上accessor关系子修饰的属性,向当于声明类getter和setter
function logged(value, context:ClassAccessorDecoratorContext){
if(context.kind === 'accessor'){
const { get, set } = value
return {
get(){
return get.call(this)
}
set(val){
console.log(val)
set.call(this, val)
}
init(initValue){
return initValue
}
}
}
}
class Test {
accessor name = 'aa';
// name = 'aa'
// get name(){
// return this.name
// }
// set name(value){
// this.name = value
// }
}
自定义类型声明文件
- xxx.d.ts
declare let count: number;
interface Point {
x: number;
y: number;
}
declare let position: Point;
declare funcition add(x:number, y:number):number
type FomartPoint = (point: Point)=>void
declare const fomartPoint: FonmarePoint;
// 需要导出声明好的类型,才能在其他的 .ts 文件中使用
export {count, position, add, fomartPoint}
//声明文件或模块的语法格式如下:
declare module Module_Name {
}
declare module 'xxx' {
interface RouteMeta{
keepalive?: boolean;
title: string;
}
}
export{};//告诉ts这是一个模块,否则可能不起作用
// global.d.ts 声明全局global格式如下:
export{};
declare global {
interface Window{
dd: any;
}
}
tsconfig.json配置规则
{
/* 根选项 */
"include": ["./src/**/*"], // 指定被编译文件所在的目录
"exclude": [], // 指定不需要被编译的目录
//使用小技巧:在填写路径时 ** 表示任意目录, * 表示任意文件。
/* 项目选项 */
"compilerOptions": {
"target": "ES6", // 目标语言的版本
"module": "commonjs", // 生成代码的模板标准
"lib": ["DOM","ES5","ES6","ES7","ScriptHost"], // TS需要引用的库
"outDir": "./dist", // 指定输出目录
"rootDir": "./", // 指定输出文件目录(用于输出),用于控制输出目录结构
"allowJs": true, // 允许编译器编译JS,JSX文件
"checkJs": true, // 允许在JS文件中报错,通常与allowJS一起使用
"removeComments": true, // 删除注释
"esModuleInterop": true, // 允许export=导出,由import from 导入
/* 严格检查选项 */
"strict": true, // 开启所有严格的类型检查
"alwaysStrict": true, // 在代码中注入'use strict'
"noImplicitAny": true, // 不允许隐式的any类型
"noImplicitThis": true, // 不允许this有隐式的any类型
"strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量
"strictBindCallApply": true, // 严格的bind/call/apply检查
"strictFunctionTypes": true, // 不允许函数参数双向协变
"strictPropertyInitialization": true, // 类的实例属性必须初始化
/* 额外检查 */
"noUnusedLocals": true,//是否检查未使用的局部变量
"noUnusedParameters": true,//是否检查未使用的参数
"noImplicitReturns": true,//检查函数是否不含有隐式返回值
"noImplicitOverride": true,//是否检查子类继承自基类时,其重载的函数命名与基类的函数不同步问题
"noFallthroughCasesInSwitch": true,//检查switch中是否含有case没有使用break跳出
"noUncheckedIndexedAccess": true,//是否通过索引签名来描述对象上有未知键但已知值的对象
"noPropertyAccessFromIndexSignature": true,//是否通过" . “(obj.key) 语法访问字段和"索引”( obj[“key”]), 以及在类型中声明属性的方式之间的一致性
/* 实验选项 */
"experimentalDecorators": true,//是否启用对装饰器的实验性支持,装饰器是一种语言特性,还没有完全被 JavaScript 规范批准
"emitDecoratorMetadata": true,//为装饰器启用对发出类型元数据的实验性支持
/* 高级选项 */
"forceConsistentCasingInFileNames": true,//是否区分文件系统大小写规则
"extendedDiagnostics": false,//是否查看 TS 在编译时花费的时间
"noEmitOnError": true,//有错误时不进行编译
"resolveJsonModule": true,//是否解析 JSON 模块
},
}
推荐文章
-
2024-02-16 04:50:49 浏览量: 1002
-
2024-02-16 04:35:05 浏览量: 1002
-
2024-02-16 04:41:12 浏览量: 1002
-
2024-04-20 17:25:17 浏览量: 1024
-
2024-03-17 07:12:40 浏览量: 1015
-
2024-04-24 19:57:51 浏览量: 1117
-
2024-04-17 14:24:51 浏览量: 1010
-
2024-05-16 10:08:01 浏览量: 1012
-
2024-05-18 18:17:35 浏览量: 1009
-
2024-02-23 17:39:12 浏览量: 1011
-
2024-05-04 10:37:44 浏览量: 1013
-
2024-04-24 08:00:02 浏览量: 1017
-
2024-05-05 06:27:43 浏览量: 1016
-
2024-05-18 18:26:30 浏览量: 1004
-
2024-03-15 08:46:32 浏览量: 1016
-
2024-03-22 13:42:22 浏览量: 1020
-
2024-04-06 10:10:52 浏览量: 1025
-
2024-05-18 18:29:25 浏览量: 1012
-
2024-03-21 00:57:53 浏览量: 1010
-
2024-02-29 09:32:30 浏览量: 1009