前言🔥
- typescript为了什么
- 为了编写代码提供丰富的语法提示
- 并对代码进行类型检测 从而避免很多线上错误
- ts是js的超集 遵循最新的ES5/ES6规范。
- ts扩展了js语法。
- 以下是总结的typescript一些基础用法
基础类型
1.数字 布尔 字符串
let num1: number = 1
let num2: Number = 1
let num3: number = Number('1')
let num4: Number = new Number(1)
let num4: number = new Number(1)
let num: number = 1
let str: string = 'Tom'
let bool: boolean = true
2.数组
const arr1: number[] = []
const arr2: (number | string)[] = ['a', 1]
const arr3: any[] = ['a', 1, {}]
const arr4: Array<boolean> = [true, false]
const arr4: Array<number | string> = [1, '2', 3]
3.元组
const tuple: [string, boolean, number] = ['a', true, 1]
tuple.push('a', 1, true)
tuple.push('a', 1, {})
tuple[3] = 100
const r = tuple.pop()
4.枚举
enum TOM {
NAME,
AGE,
HEIGHT = 10,
BRPTHER,
ADDRESS
}
console.log(TOM[0])
console.log(TOM.NAME)
console.log(TOM.AGE)
console.log(TOM.HEIGHT)
console.log(TOM.BRPTHER)
console.log(TOM[NAME])
enum BOB {
NAME = 'name',
AGE = 'age',
HEIGHT = 'height',
BRPTHER = 'brother',
NUMBER = 10,
ADDRESS = 'address'
}
console.log(BOB.NAME)
console.log(BOB['name'])
console.log(BOB.NUMBER, BOB[10])
const enum MAY {
NAME,
AGE,
HEIGHT
}
console.log(MAY.NAME)
console.log(MAY[0])
5.any
const arr:any = [ 'Tom', true, {age: '30'} ]
6.null undefined
let u: undefined = undefined
let n: null = null
let n2: string = null
let n2: string = null
7.never
function loop(): never {
while (true) {}
}
function fn(x:number | string) {
if (typeof x == 'number') {
} else if (typeof x === 'string') {
}else{
console.log(x)
}
}
function error(message: string): never {
throw new Error("err")
}
8.void
function fn1(): void { console.log('void') }
function fn1(): void { return undefined }
function fn2(): void { return null }
function fn2(): void { return null }
let v: void = undefined
let v: void = null
let v: void = undefined
let v: void = null
9.object
const create = (obj: object): void => {}
create({})
create([])
create(function(){})
create('string')
10.Symbol BigInt
let s1: symbol = Symbol(1)
let s2: symbol = Symbol(2)
console.log(s1 === s2)
let max = Number.MAX_SAFE_INTEGER
let b1:bigint = BigInt(max)
console.log(max + b1)
console.log(BigInt(max) + b1)
console.log(BigInt(max) + 1)
console.log(BigInt(max) + '1')
console.log(BigInt(max) + BigInt(1) === BigInt(max) + BigInt(2))
类型推导
1.类型推导
let name1;
let name2 = 'zhufeng'
name2 = 30
2.联合类型
let numOrStr: string | number;
numOrStr = 'a'
numOrStr = 1
3.断言
非空断言(!)
const el: HTMLElement | null | undefined = document.getElementById('app')
el!.innerHTML = 'el-app'
类型断言(as, <>)
let a1: string | number | undefined;
(a1 as string).length
(<string>a1).length
双重断言
let name3: string | number;
let x = (name3! as any) as boolean;
x = true
4.字面量
type Direction = 'Up' | 'Down' | 'Left' | 'Right'
let direction:Direction = 'Up'
type IObj = {name:string, age:number} | string
函数类型
1.声明方式
function sum(a: string, b: string):string {
return a + b
}
sum('a', 'b')
type Sum2 = (a1: number, b1: number) => number;
let sum2: Sum2 = (x, y) => {
return x + y
}
sum2(1, 2)
2.可选参数 剩余参数 默认参数
- 可选参数必须在其他参数的最后面
- 默认值和可选参数不能一起使用
let sum3 = (a: string, b?: string):string => {
return a + b
}
sum3('a')
const sum4 = (x: number, y?: number, ...args: number[]): number => {
return x + (y as number)
}
sum4(1)
sum4(1, 2)
let sum5 = (a: string, b: string = 'b'): string => {
return a + b
}
sum5('a')
3.函数重载
function toArray1(value:string | number) {
if(typeof value == 'string'){
return value.split('')
}else{
return value.toString().split('').map(item=>Number(item))
}
}
let r1 = toArray1('abc')
function toArray2(value:string):string[]
function toArray2(value:number):number[]
function toArray2(value:string | number) {
if(typeof value == 'string'){
return value.split('')
}else{
return value.toString().split('').map(item=>Number(item))
}
}
let r2 = toArray2('abc')
class类
1.定义
class Pointer{
x!:number;
y!:number;
constructor(x: number, y?:number, ...args:number[]){
this.x = x
this.y = y as number
}
}
let p1 = new Pointer(100, 100)
2.修饰符
public 谁都可以访问到
protected 只有自己和自己的后代 能访问
private 就是只有自己能访问的属性
readonly 仅读 (与const类似) 初始化完毕后不能在修改了 但是对象可以更改属性
class Animal {
public name!: string;
public age!: number;
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
class Cat extends Animal {
constructor(name: string, age: number) {
super(name, age)
console.log(this.name, this.age)
}
}
let p2 = new Cat('Tom', 30)
console.log(p2.name, p2.age)
class Animal3 {
constructor(protected name: string, protected age: number) {
this.name = name
this.age = age
}
}
class Cat3 extends Animal3 {
constructor(name: string, age: number) {
super(name, age)
console.log(this.name, this.age)
}
}
let p3 = new Cat3('Tom', 30)
console.log(p3.name, p3.age)
class Animal4 {
constructor(private name: string, private age: number) {
this.name = name
this.age = age
}
}
class Cat4 extends Animal4 {
constructor(name: string, age: number) {
super(name, age)
console.log(this.name, this.age)
}
}
let p4 = new Cat4('Tom', 30);
console.log(p4.name, p4.age)
class Animal5 {
public readonly n: number = 1
constructor(public readonly name: string, public age: number) {
this.name = name
this.age = age
}
getN() {
console.log(this.n)
}
}
class Cat5 extends Animal5 {
constructor(name: string, age: number) {
super(name, age)
}
}
let p5 = new Cat5('Tom', 30)
p5.getN()
3.静态属性和方法, 以及属性访问器(非ts)
static, set, get
- 静态属性, es7语法, 通过类访问
- 静态方法, es6语法, 通过类访问
- 属性访问, es6语法, 通过实例访问
class Animal6 {
static type = '哺乳动物'
static getName() {
return '动物'
}
private _name: string = 'Tom'
get name() {
return this._name
}
set name(name: string) {
this._name = name
}
}
class Cat6 extends Animal6 {
constructor() {
super()
console.log(Cat6.type)
}
}
let p6 = new Animal6()
console.log(p6.name, Animal6.getName(), Animal6.type)
let c6 = new Cat6()
console.log(Cat6.getName())
4.super属性(非ts)
super
- 子类继承父类, 在使用父类属性方法时, 必须在子类
constructor第一行调用super()
class Animal {
say(message:string) { console.log(message) }
static getType() { return '动物' }
}
class Cat extends Animal {
constructor() {
super()
}
say() { super.say('猫咪') }
static getType(){ return super.getType() }
}
let cat = new Cat()
console.log(Cat.getType(), cat.say())
5.类的装饰器
- es7语法
- 干什么用的
- 可以给类扩展功能 扩展类中的属性和方法
- 也可以复用扩展功能
- 不能修饰函数 函数会有变量提升的问题
- 前提说明
- 装饰器 目前仍是一个实验性语法
- 需要开启(ts配置文件)
experimentalDecorators:true
- 装饰器要挨着修饰的类 或者类的方法 或者类的属性(中间空格无所谓, 主要是不要有其他无关代码)
执行顺序
function addSay1(val: string) {
console.log(val)
return function (target: any) { console.log(1) }
}
function addSay2(val: string) {
console.log(val)
return function (target: any) { console.log(2) }
}
function addSay3(val: string) {
console.log(val)
return function (target: any) { console.log(3) }
}
@addSay1('a1')
@addSay2('a2')
@addSay3('a3')
class Person {}
let person = new Person()
装饰类
@log
class MyClass {
logger!: Function
}
function log(target:any) {
target.prototype.logger = () => `${target.name} 被调用`
}
const t1 = new MyClass()
console.log(t1.logger())
装饰类中属性
function toUpperCase(target:any, key:string){
let value = target[key]
Object.defineProperty(target, key, {
get() {
return value.toUpperCase()
},
set(newValue) {
value = newValue
}
})
}
class Person {
@toUpperCase
public name: string = 'tom'
}
let p1 = new Person()
console.log(p1.name)
function double(target: any, key: string) {
let value = target[key]
Object.defineProperty(target, key, {
get() {
return value * 2
},
set(newValue) {value = newValue}
})
}
class Person {
@double
static age: number = 10
}
let person = new Person()
console.log(Person.age)
装饰类的方法
function noEnum(target:any, key:string, descriptor:PropertyDescriptor){
descriptor.enumerable = false
}
class Person {
name = 'bob'
@noEnum
getName() { return 'Tom' }
}
let person = new Person()
for (const key in person) {
console.log(key)
}
装饰类的参数
function addPrefix(target:any, key:string, paramIndex:number){
console.log(target, key, paramIndex)
}
class Person {
getName(@addPrefix prefix:string) {
return prefix
}
}
let p1 = new Person()
console.log(p1.getName('tom'))
抽象类
- 抽象类无法被实例化 只能被继承
- 抽象方法不能在抽象类中实现
- 只能在抽象类的具体子类中实现 而且必须实现
abstract class Animal{
name!:string;
abstract speak():void
}
class Cat extends Animal {
speak(): string {
console.log('猫')
return '123456'
}
}
let c = new Cat()
console.log(c.speak())
接口(interface)
interface 与 type 的区别
interface 可以被类实现和继承 但是type没有
type 可以使用联合类型 interface不能使用联合类型
1.接口的定义
interface IObj {
name: string
age: number
}
const getObj = (obj: IObj) => { console.log(obj.name, obj.age) }
getObj({ name: 'tom', age: 30 })
2.描述函数
interface ISum {
(a: number, b: number): number
}
const sum:ISum = (a, b) => { return a + b }
3.描述函数与自定义属性(混合类型)
interface IFnCount {
(): number,
count: number
}
const fnCount:IFnCount = () => { return ++fnCount.count }
fnCount.count = 0
4.对象(接口的特性)
as 断言
interface IVegetables {
color: string;
taste: string;
}
const tomato: IVegetables = {
color: 'red',
taste: 'sweet',
size: 'small'
} as IVegetables
接口合并
interface IVegetables2 {
color: string;
taste: string;
}
interface IVegetables2 {
size:string
}
const tomato2:IVegetables2 = {
color:'red',
taste:'sweet',
size:'big'
}
接口继承
interface IVegetables3 {
color: string;
taste: string;
}
interface ITomato3 extends IVegetables3 {
size: string
}
const tomato3:ITomato3 = {
color:'red',
taste:'sweet',
size:'big'
}
可选属性(?:)
interface IVegetables4 {
color: string,
taste: string,
[key: string]: any
}
const tomato4:IVegetables4 = {
color:'red',
taste:'sweet',
size:'big',
id: 4,
[Symbol()]: 'tomato4'
}
索引接口
interface IArr {
[key: number]: number
}
let arr1: IArr = [ 1, 2, 3 ]
let arr2: IArr = { 1: 1, 2: 2, 3: 3 }
5.如何获取接口中的类型
type TA = {key: string, vlaue: string}
interface ITreeItem {
items: TA[]
}
interface ITree {
name: string,
sub: ITreeItem
}
type GetSub = ITree['sub']['items']
6.描述类(implements)
interface ISpeakable {
name: string,
speak(): void
}
interface IChineseSpeakable {
speakChinese(): void
}
class Speak implements ISpeakable, IChineseSpeakable {
name!: string
speak(): void {
throw new Error("Method not implemented.")
}
speakChinese(): string {
return ''
}
}
7.描述类实例
interface IClazz {
new(name: string): Person
}
function createInstance(clazz: IClazz, name: string) {
return new clazz(name)
}
class Person {
constructor(public name: string) {}
eat() { console.log('Person ~ eat') }
}
let p = createInstance(Person, 'tom')
interface IClazz2<T> {
new(name: string): T
}
function createInstance2<T>(clazz: IClazz2<T>, name: string) {
return new clazz(name)
}
class Person2 {
constructor(public name: string) {}
eat() {}
}
class Animal2 {
constructor(public name: string) { }
drink() {}
}
let pOrA = createInstance2<Animal2>(Animal2, 'tom')
泛型
- 泛型的用处在于 一开始不知道类型 只有当我们调用的时候 确定类型
- 类型不确定 只有在执行的时候才能确定
1.单个泛型
const getArr = <T>(len: number, val: T): T[] => {
let res:T[] = []
for (let i = 0; i < len; i++) {
res.push(val)
}
return res
}
let arr = getArr(3, 4)
2.多个泛型
function swap<T, K>(tuple: [T, K]): [K, T] {
return [tuple[1], tuple[0]]
}
console.log(swap(['a', 1]))
3.约束对象
必须包含某些属性
interface IWithLength {
length: number
}
const computeArrayLength= <T extends IWithLength, K extends IWithLength>(arr1:T, arr2:K):number => {
return arr1.length + arr2.length
}
computeArrayLength('123', {length:3})
interface IWithLength2 {
size: string
}
const computeArrayLength2= <T extends IWithLength2, K extends IWithLength2>(obj1:T, obj2:K):string =>{
return obj1.size + obj2.size
}
console.log(computeArrayLength2({ size: 'a' }, { size: 'b' }))
const sum = <T extends string>(a: T, b: T): T => {
return (a + b) as T
}
sum('a','v')
返回指定的类型
const getVal = <T extends object, K extends keyof T>(obj:T, key:K): T[K] => {
return obj[key]
}
console.log('keyof', getVal({a:1, b:2}, 'a'))
type getObjKeys = keyof {a:1, b:2}
let objKey: getObjKeys = 'b'
type getAnyKeys = keyof any
4.类型别名
interface IArray{
<T,K>(typle:[T,K]):[K,T]
}
const getArray:IArray = <T, K>(tuple: [T, K]): [K, T] => {
return [tuple[1], tuple[0]]
}
let r = getArray([3,'a'])
5.默认泛型
interface IDefault<T=string> {
name: T
}
let name1:IDefault = { name: 'tom' }
type IDefault2 = IDefault<number>
let name2:IDefault2 = { name: 123 }
类型保护
- 靠的是js特性和ts自带的功能
- js 通过判断识别所执行的代码块 自动识别变量属性和方法
1.typeof (js特性)
function typeofFn(val: string | number) {
if (typeof val == 'string') {
val.split
} else {
val.toFixed
}
}
2.instanceof (js特性)
class Person {
speak() {}
}
class Animal {
noSpeak() {}
}
interface IClazz {
new (): Person | Animal
}
const createClass = (clazz: IClazz) => {
return new clazz
}
let pOrA = createClass(Person)
if (pOrA instanceof Person) {
pOrA.speak
} else {
pOrA.noSpeak
}
3.in (js特性)
interface Fish {
swiming: string,
}
interface Bird {
fly: string,
leg: number
}
function getTypeIn(animal: Fish | Bird) {
if ('swiming' in animal) {
animal
} else {
animal
}
}
getTypeIn({swiming: 'swiming'})
4.is 自定义类型保护(ts特有)
interface Fish2 {
swiming: string,
}
interface Bird2 {
fly: string,
leg: number
}
function isFish2(animal: Fish2 | Bird2): animal is Fish2 {
return 'swiming' in animal
}
function getTypeIn2(animal: Fish2 | Bird2) {
if (isFish2(animal)) {
animal
} else {
animal
}
}
5.null保护
const addPrefix = (num: number | null) => {
num = num || 30
function prefix(fix: string) {
if (num) {
return fix + num.toFixed
}
}
return prefix('tom')
}
6.完整性保护
interface ISquare {
kind: 'square',
width: number
}
interface IRant {
kind: 'rant',
width: number,
height: number
}
interface ICircle {
kind: 'circle',
r: number
}
const assert = (obj: never) => { throw new Error("err") }
function getArea(obj: ISquare | IRant | ICircle) {
switch (obj.kind) {
case 'square':
return obj.width * obj.width
case 'rant':
return obj.width * obj.height
case 'circle':
return 3.14 * obj.r ** 2
default:
assert(obj)
}
}
getArea({ kind: 'circle', r: 10 })
交叉类型
1.定义
interface Person1 {
handsome: string,
}
interface Person2 {
high: string,
}
type P12 = Person1 & Person2
let p12:P12 = { handsome: '帅', high: '高' }
type Person3 = Person2 & { money: string }
let p123: Person3 = {
...p12,
money: '钱'
}
2.冲突(never)
interface IPerson1 {
name:string,
age:number
}
interface IPerson2 {
name:number
age:number
}
type person = IPerson1 & IPerson2
3.函数
function mixin<T extends object, K extends object>(a: T, b: K): T & K {
return {...a, ...b}
}
const x = mixin({}, {name: 'tom', age: 30 })
兼容性
- 主要看结构是否兼容
- 核心是考虑安全性
- 从安全角度出发
1.普通类型
let strOrNum:string | number
let num!:number
strOrNum = num
type IToStr = {
toString(): string,
length: number
}
let name: IToStr = 'tom'
2.接口兼容性
interface IVegetables {
color: string,
taste: string
}
interface ITomato{
color: string,
taste: string,
size: string
}
let vegetables: IVegetables;
let tomato:ITomato = {
color: 'red',
taste: 'sour',
size: 'big'
}
vegetables = tomato
3.函数兼容性
let sum1 = (a: string, b: string): string => a + b
let sum2 = (a: string): string => a
sum1 = sum2
console.log(sum1('1', '2'))
function forEach<T>(arr: T[], cb: (item: T, index: number, arr: T[]) => void) {
for (let i = 0; i < arr.length; i++) {
cb(arr[i], i, arr)
}
}
forEach([1, 2, 3, 4], (item) => {
console.log(item)
})
type Sum3 = (a: string, b: string) => { name: string }
type Sum4 = (a: string) => { name: string, age: number }
let sum3!: Sum3;
let sum4!: Sum4;
sum3 = sum4
4.函数的逆变和协变
class Parent {
money: string = '100000000000'
}
class Child extends Parent {
house: string = '豪华'
}
class Grandson extends Child {
eat: string = '美食'
}
function getFn(cb: (person: Child) => Child) {
return cb(new Grandson)
}
let r = getFn((person: Parent) => new Grandson)
5.联合类型
function getType(cb: (val: string | number) => string | number) {
cb('123456')
}
getType((val: string|number|boolean): string => {
return val as string
})
6.泛型
interface IO<T>{}
let obj1:IO<string>;
let obj2!:IO<number>;
obj1 = obj2
7.枚举
enum USER1 {
role = 1
}
enum USER2 {
role = 1
}
let user1!:USER1
let user2!:USER2
条件类型
基本使用
interface Fish {
name: string,
type: '鱼'
}
interface Bird {
name: string,
type: '鸟'
}
interface Swiming {
swiming: string
}
interface Sky {
sky: string
}
type ExprType<T> = T extends Fish ? Swiming : Sky
type ResT1 = ExprType<Fish>
let fish:ResT1 = {
swiming: '游'
}
interface ISchool1 {
name: string,
age: number
}
interface ISchool2 {
age?: number,
size: string
}
type School<T> = T extends { name: string } ? ISchool1 : ISchool2
type MySchool = School<ISchool2>
let mySchool: MySchool = {
size: 'size'
}
2.条件类型分发
interface Fish {
name: string,
type: '鱼'
}
interface Bird {
name: string,
type: '鸟'
}
interface Swiming {
swiming: string
}
interface Sky {
sky: string
}
type ExprType<T> = T extends Fish ? Swiming : Sky
type ResT2 = ExprType<Fish|Bird>
let fOrB:ResT2 = {
sky: '飞'
}
3.ts内置类型
Exclude 排除类型
type Exclude<T, K> = T extends K ? never : T
type MyExclude = Exclude<string | number | boolean, boolean>
let myExclude: MyExclude = '123'
Extract 抽取类型
type Extract<T, K> = T extends K ? T : never
type MyExtract = Extract<string | number | boolean, boolean>
let myExtract = true
NoNullable 非空检测
type NonNullable<T> = T extends null | undefined ? never : T
type MyNonNullable = NonNullable<string | number | null | undefined>
let myNonNullable: MyNonNullable = 123
4.类型推断(infer)
- ts内置类型
- infer要配合 extends 否则无法使用
- infer有推断类型的功能 可以自动推断出结果
- infer放在哪里 就是推断哪里的结果
ReturnType 返回值类型
function getUser(a: string, b: number) {
return { name: a, age: b }
}
type ReturnType<T extends ((...args: any[])=> any) > = T extends ((...args: any[]) => infer R) ? R : any
type MyReturnType = ReturnType<typeof getUser>
let myReturnType: MyReturnType
Parameters 参数类型
type Parameters<T extends ((...args: any)=> any)> = T extends ((...args: infer P) => any) ? P : any
type MyParameters =Parameters<typeof getUser>
let myParameters:MyParameters = ['tom', 30]
ConstructorParameters 构造函数参数类型
class Person {
name: string = 'tom'
age: number = 30
constructor(name:string) {}
}
type ConstructorParameters<T extends new (...args: any[])=> any> = T extends new (...args: infer CP)=> any ? CP : any
type MyConstructorParameters = ConstructorParameters<typeof Person>
let myConstructorParameters: MyConstructorParameters = ['tom']
InstanceType 实例类型
type InstanceType<T> = T extends { new(...args: any): infer R } ? R : any
type MyInstance = InstanceType<typeof Person>
let myInstance: MyInstance = { name: 'bob', age: 25 }
5.实践
type Tuple = [string, boolean, number]
type ElementOf<T> = T extends Array<infer E> ? E : never
type TupleToUnion = ElementOf<Tuple>
type T1 = { name: string }
type T2 = { age: number }
type ToIntersection<T> = T extends Array<(x: infer U) => any> ? U : never
type T3 = ToIntersection<[(x:T1)=>any, (x:T2)=>any]>
let myT3: T3 = {
name: 'tom',
age: 30
}
内置类型
1.Partial转化为可选属性
interface ICompany {
name: string,
address: string,
size?: string
}
interface IPerson {
name?: string,
age: number,
company?: ICompany
}
type Partial<T> = { [K in keyof T]?: T[K] }
type MyPartial = Partial<IPerson>
let myPartial!:MyPartial
2.Required 去掉可选
interface ICompany2 {
name?: string,
address?: string,
size?: string
}
type Required<T> = { [K in keyof T]-?: T[K] }
type MyRequired = Required<ICompany2>
let myRequired!:MyRequired
3.Readonly 仅读属性
interface ICompany3 {
name?: string,
address?: string,
size?: string
}
type Readonly<T> = { readonly [K in keyof T]: T[K] }
type MyReadonly = Readonly<ICompany3>
let myReadonly:MyReadonly = {
name: 'tom'
}
4.Pick 挑选所需的属性
interface ICompany4 {
name?: string,
address?: string,
size?: string
}
type Pick<T, K extends keyof T> = { [X in K]: T[X] }
type MyPick = Pick<ICompany4, 'name' | 'address'>
let myPick!:MyPick
5.Qmit 忽略属性
interface ICompany5 {
name: string,
address: string,
size: string
}
type Exclude<T, K> = T extends K ? never : T
type Qmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
type MyOmit = Qmit<ICompany5, 'name'>
6.Record记录类型
type Record<K extends keyof any, T> = { [P in K] : T }
let person: Record<'name' | 'age', any> = { name: 'tom', age: 30 }
function map<K extends string | number | symbol, V, X>(obj: Record<K, V>, cb: (item: V, key: K) => X): Record<K, X> {
let result = {} as Record<K, X>
for (const key in obj) {
result[key] = cb(obj[key], key)
}
return result
}
let m = map({name: 'tom', age: 30}, (item) => {
return '$' + item
})
interface PageInfo {
title: string;
}
type Page = "home" | "about" | "contact"
const nav: Record<Page, PageInfo> = {
about: { title: "about" },
contact: { title: "contact" },
home: { title: "home" },
}
自定义类型
1.裝包与拆包
let data = {
name: 'tom',
age: 30
}
interface Proxy<T> {
get() : T,
set(value: any): void
}
type Proxify<T> = {
[K in keyof T]: Proxy<T[K]>
}
function proxify<T extends object>(obj: T):Proxify<T> {
let result = {} as Proxify<T>
for (const key in obj) {
let value = obj[key]
result[key] = {
get () {
return value
},
set(newValue: T[Extract<keyof T, string>]) {
value = newValue
}
}
}
return result
}
let proxyData = proxify(data)
console.log(proxyData.name.get())
proxyData.name.set('bob')
console.log(proxyData.name.get())
function unProxify<T extends object>(obj: Proxify<T>): T {
let result = {} as T
for (let key in obj) {
let value = obj[key]
result[key] = value.get()
}
return result
}
let unProxifyData = unProxify(proxyData)
2.接口取差集, 交集
let person1 = {
name: 'tom',
age: 30,
address: '地球'
}
let person2: {
address: '地球'
}
type Diff<T extends object, K extends object> = Omit<T, keyof K>
type MyDiff = Diff<typeof person1, typeof person2>
type Inter<T extends object, K extends object> = Pick<K, Extract<keyof T, keyof K>>
type MyInter = Inter<typeof person1, typeof person2>
3.解决& 属性出现never问题
type Person1 = {
age: number,
name: string
}
type Person2 = {
age: string,
address: string
}
type Merge<T extends object, K extends object> = Omit<T, keyof K> & K
type Compute<T> = { [K in keyof T]: T[K] }
type MyMerge = Compute<Merge<Person1, Person2>>
unknown
let name: unknown = 1
type X = boolean | unknown
type Y = boolean & unknown
type S = keyof unknown
命名空间
1.内部模块
- 使用命名空间来声明 解决同一个文件下的命名冲突问题
namespace 关键字
module 关键字(最终还是转成namespace 所以建议使用namespace)
- 命名空间就是通过自执行函数来是实现的
使用
export namespace zoo {
export class Dog { eat() { console.log('zoo dog') } }
export let address = '动物园'
}
export namespace home {
export class Dog { eat() { console.log('home dog') } }
export let address = '家里'
}
let dog_of_zoo = new zoo.Dog()
dog_of_zoo.eat()
dog_of_zoo.address
let dog_of_home = new home.Dog()
dog_of_home.eat()
嵌套使用
export namespace zoo {
export class Dog { eat() { console.log('zoo dog') } }
export namespace bear{
export const name = '熊'
}
}
console.log(zoo.bear.name)
特殊情况
namespace Home {
export const a = 'a'
}
module Home {
export class Dog{}
export const b = 'b'
}
console.log(new Home.Dog, Home.a, Home.b)
2.外部模块
export import语法 ESModule
require module.exports语法 commonjs
- cjs模块 ts单独的提供一个导出方式
export = / import x = require(''), 因为cjs没有类型提示
- es6模块 全部用
export , default export {} / import 不变
es6例子
export default 'tom'
import name from './a'
console.log(name)
cjs例子
import r = require('fs')
导入导出规范
import $ from 'jquery'
const $ = require('jquery')
import * as $ from 'jquery'
import $ = require('jquery')
类型声明
1.声明全局变量
declare 关键字
- 没有确切的含义 只是为了防止出错
declare let age: number
declare function sum(a: string, b: string): void
declare class Animal { }
declare const enum Seaons{
Spring,
Summer,
Autumn,
Winter
}
declare interface Person {
name:string,
age:number
}
let u: number = Seaons.Autumn
sum('a', 'b')
export {}
declare const $:(selector:string)=>{
height(num?:number):void
width(num?:number):void
}
$('').height()
declare namespace jQuery {
function ajax(url:string,otpions:object):void;
namespace fn {
function extend(obj:object):void
}
}
jQuery.ajax('/',{})
jQuery.fn.extend({})
2.类型声明文件
- 类型声明文件以
文件名.d.ts 结尾
- 默认在项目编译时会查找所有以
.d.ts结尾的文件
declare const $:(selector:string)=>{
height(num?:number):void
width(num?:number):void
}
declare namespace jQuery {
function ajax(url:string,otpions:object):void
namespace fn {
function extend(obj:object):void
}
}
declare module '*.vue' {
import { defineComponent, App } from 'vue';
const component: ReturnType<typeof defineComponent>;
export default component
}
3.编写第三方声明文件
* 配置tsconfig.json
* "moduleResolution": "node",
* "baseUrl": "./",
* "paths": {
* "*": ["types/*"]
* },
declare function jQuery(selector: string): HTMLElement
declare namespace jQuery {
function ajax(url: string): void
}
export = jQuery
4.第三方声明文件
* @types是一个约定的前缀,所有的第三方声明的类型库都会带有这样的前缀
* `npm install @types/jquery -S`
* 当使用jquery时默认会查找 node_modules/@types/jquery/index.d.ts 文件
* 查找规范
1. node_modules/jquery/package.json 中的types字段
2. node_modules/jquery/index.d.ts
3. node_modules/@types/jquery/index.d.ts
扩展全局变量类型
1.局部变量
interface String {
double():string
}
String.prototype.double = function () {
return this as string + this
}
let str = 'tom'
interface Window {
mynane:string
}
console.log(window.mynane)
2.模块内扩展全局变量
declare global{
interface String {
double():string
}
interface Window{
myname:string
}
}
export {}