初识TypeScript

Posted 403 Forbidden

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初识TypeScript相关的知识,希望对你有一定的参考价值。

学习ts之前, 应当对js有一定的了解

简介

TS包含JS, 是JS的超集, 需要编译才能被浏览器识别.
全局安装TS

$npm install -g typescript

没有修改npm为国内源的可以执行以下代码

$npm config set registry http://registry.npm.taobao.org
$npm get registry
http://registry.npm.taobao.org/

查看TS版本:

$>tsc -V
Version 4.5.3

简单使用

先创建一个ts文件, 暂时使用ts的语法写一段代码

/* ts01.ts 文件 */
(
    () => 
        function sayHi(str: string) 
            return "你好" + str
        

        let text = "lczmx";
        console.log(sayHi((text)));
    
)()

然后使用html文件引用:

<!DOCTYPE html>
<html lang="en">
<head>
    
    <title>Ts01</title>
</head>
<body>
<!-- html文件与ts文件同级 -->
<script src="./ts01.ts"></script>
</body>
</html>

使用浏览器打开, 发现报错, 原因是浏览器无法识别ts的语法:

最后编译tsjs, 再次引用:

$tsc ts01.ts
$ls
index.html  ts01.js  ts01.ts

以上命令会在源目录下生成相同文件名的js文件

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    
    <title>Ts01</title>
</head>
<body>
<!-- html文件与js文件同级 -->
<script src="./ts01.js"></script>
</body>
</html>

成功执行:

感兴趣的可以看看编译后的js长什么样

TS自动编译

  1. 执行命令, 生成tsconfig.json文件
    $tsc --init
    
  2. 修改配置
    主要修改:
    "outDir": "./js",   /* 把编译后的文件放到js目录下 */
    "strict": false,   /* 不使用严格模式 */               
    
  3. 启动监听任务
    $tsc -p tsconfig.json --watch
    [下午11:20:35] Starting compilation in watch mode...
    [下午11:20:37] Found 0 errors. Watching for file changes.
    

以上, 当我们修改ts文件时, tsc就会自动在js目录下, 编译成对应的js文件

类型注解

即像上面的代码那样使用:为参数作类型的约束, 类型不对时, ts会报错, 但仍然会生成对应的js文件.
例子:

(() => 
    function showMsg(str: string) 
        return "show: " + str
    

    let message = "hello world";
    showMsg(message);
    let m2 = [1, 2, 3];
    showMsg(m2) // 报错, 但还会生成js文件
)()

js中怎样写, ts就怎样写

(() => 
    // 定义接口
    interface IPerson 
        firstName: string  // 姓
        lastName: string  // 名
    

    // 定义一个类
    class Person 
        // 定义公共字段(属性)
        firstName: string
        lastName: string
        fullName: string

        // 定义一个构造函数
        constructor(firstNme: string, lastName: string) 
            // 更新属性数据
            this.firstName = firstNme
            this.lastName = lastName
            this.fullName = this.firstName + this.lastName
        

    

    // 定义一个函数
    function showFullName(person: IPerson) 
        return person.firstName + person.lastName
    
    // 实例化对象
    const person = new Person("邢", "道荣")
    console.log(showFullName(person))

)()

TypeScript里的类只是一个语法糖,本质上还是JavaScript函数的实现。

使用webpack打包TS

初始化

生成package.jsontsconfig.json

$npm init -y
$tsc --init

下载依赖

$npm install -D typescript
$npm install -D webpack webpack-cli webpack-dev-server
$npm install -D html-webpack-plugin clean-webpack-plugin
$npm install -D ts-loader
$npm install -D cross-env

上面这些包的作用:

  • typescript 提供TS支持
  • webpack 打包工具
  • webpack-cli 为webpack提供开发指令
  • webpack-dev-server 打包时提供的服务器 (可用于开发)
  • html-webpack-plugin 打包html
  • clean-webpack-plugin 清除打包过程中的目录
  • ts-loader ts编译工具
  • cross-env跨平台命令支持

创建文件

文件目录结构:

├─build
├─public
└─src
  1. 入口JS: src/main.ts
document.write(\'Hello Webpack TS!\')
  1. index页面: public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
  
  
  
  <title>webpack & TS</title>
</head>
<body>
  
</body>
</html>
  1. webpack配置: build/webpack.config.js
const CleanWebpackPlugin = require(\'clean-webpack-plugin\')
const HtmlWebpackPlugin = require(\'html-webpack-plugin\')
const path = require(\'path\')

const isProd = process.env.NODE_ENV === \'production\' // 是否生产环境

function resolve (dir) 
  return path.resolve(__dirname, \'..\', dir)


module.exports = 
  mode: isProd ? \'production\' : \'development\',
  entry: 
    app: \'./src/main.ts\'
  ,

  output: 
    path: resolve(\'dist\'),
    filename: \'[name].[contenthash:8].js\'
  ,

  module: 
    rules: [
      
        test: /\\.tsx?$/,
        use: \'ts-loader\',
        include: [resolve(\'src\')]
      
    ]
  ,

  plugins: [
    new CleanWebpackPlugin(
    ),

    new HtmlWebpackPlugin(
      template: \'./public/index.html\'
    )
  ],

  resolve: 
    extensions: [\'.ts\', \'.tsx\', \'.js\']
  ,

  devtool: isProd ? \'cheap-module-source-map\' : \'cheap-module-eval-source-map\',

  devServer: 
    host: \'localhost\', // 主机名
    stats: \'errors-only\', // 打包日志输出输出错误信息
    port: 8081,
    open: true
  ,

配置打包命令

package.json中, 修改scripts的内容如下:

"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.js",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"

运行与打包

$npm run dev
$npm run build

基础类型

布尔值

truefalse

(() => 
    let status: boolean = false;
    status = true
    console.log(status)
)()

数字

js一样, ts的数字都是浮点数, 这些浮点数的类型都是number:

(() => 
    let a1: number = 10 // 十进制
    let a2: number = 0b1010  // 二进制
    let a3: number = 0o12 // 八进制
    let a4: number = 0xa // 十六进制
    console.log(a1, a2, a3, a4)
    // 10 10 10 10
)()

字符串

同样与js一样

(() => 
    let firstName: string = "诸葛"
    let lastName: string = "亮"

    console.log(`$firstName$lastName`)
)()

undefined和null

ts中, undefinednull两者各自有自己的类型分别叫做undefinednull
它们的本身的类型用处不是很大:

(() => 
    let a: null = null
    let b: undefined = undefined
    let name: string = null
    name = "lczmx"

    console.log(`username: $name`)
)()

默认情况下
nullundefined是所有类型的子类型, 就是说你可以把nullundefined赋值给number类型的变量

数组

两种方式: 元素类型+[] Array<元素类型>

(() => 
    let list1: number[] = [1, 2, 3, 4, 5]
    let list2: Array<number> = [6, 7, 8, 9]

    console.table(list1)
    console.table(list2)
)()

元组

元组表示一个已知元素数量和类型的数组, 且各元素的类型不必相同

(() => 
    let t1: [string, number]
    t1 = [\'hello\', 10] // OK
    t1 = [10, \'hello\'] // Error
)()

枚举

enum类型是对js标准数据类型的一个补充

(() => 
    enum Color 
        Red,
        Green,
        Blue
    

    // 枚举数值默认从0开始依次递增
    // 根据特定的名称得到对应的枚举数值
    let myColor: Color = Color.Green  // 0
    console.log(myColor, Color.Red, Color.Blue)
    // 1 0 2

    // 指定开始
    enum Color1 Red = 1, Green, Blue

    let colorName: string = Color1[2]
    console.log(colorName)  // \'Green\'
)()

any

动态类型的数据 (接收用户输入和第三方代码库), 使用any类型来标记

(() => 
    let v: any
    v = 1
    v = "maybe a string"
    v = false
)()

void

表示没有任何类型, 当一个函数没有返回值时, 你通常会见到其返回值类型是void

(() => 
    function f(): void 
        console.log("running test function")
    
    f()
)()

声明一个void类型的变量没有什么大用, 因为你只能为它赋予undefinednull

let unusable: void = undefined

object

object表示非原始类型,也就是除number string boolean之外的类型

(() => 
    function fn2(obj: object): object 
        console.log(\'fn2()\', obj)
        return 
        // return undefined
        // return null
    

    console.log(fn2(new String(\'abc\')))
    // console.log(fn2(\'abc\') // error
    console.log(fn2(String))

)()

联合类型

表示取值可以为多种类型中的一种

(() => 
    function f(x: number | string) 
        console.log(typeof x)
    
    f(123)
    f("abc")
)()

类型断言

类型断言好比其它语言里的类型转换, 但是不进行特殊的数据检查和解构
两种方式: <类型>值 值 as 类型

(() => 
    function getLength(x: number | string) 
        if ((<string>x).length) 
            return (x as string).length
         else 
            return x.toString().length
        
    

    console.log(getLength(\'abcd\'), getLength(1234))
)()

类型推断

ts会在没有明确的指定类型的时候推测出一个类型

  • 赋值时, 推断为对应的类型
  • 没有赋值, 推断为any类型
(() => 
    let name = "lczmx"
    let age

    console.log(`name type: $typeof name, age type $typeof age`)

    age = 18
)()

接口

接口是对象的状态(属性)和行为(方法)的抽象(描述), 即我们可以使用接口对 对象类型进行类型检查

简单使用

主要是给对象数据做类型注解用的

(() => 
        interface IPerson 
            firstName: string
            lastName: string
        

        function fullName(person: IPerson) 
            // 在ide中可以直接.出来
            return `$person.firstName$person.lastName`
        

        let p = 
            firstName: "东方",
            lastName: "不败"
        
        console.log(fullName(p))
    
)()

可选属性

假如某些属性不是必须的, 默认情况下都是必需的
加个?即可

(() => 
        interface IPerson 
            name: string
            age: number
            gender: boolean
            description?: string // 该属性可以省略
        

        const person: IPerson = 
            name: "lczmx",
            age: 18,
            gender: true,
        
        console.table(person)
    
)()

只读属性

一些对象属性只能在对象刚刚创建的时候修改其值
加个readonly即可

(() => 
        interface IPerson 
            readonly id: number
            name: string
            age: number
            gender: boolean
        

        const person: IPerson = 
            id: 1,
            name: "lczmx",
            age: 18,
            gender: true,
        
        console.table(person)
        // person.id = 2 //error
    
)()

变量的话用const, 属性的话用readonly

函数类型

我们也可以将函数作为使用接口表示函数
只需要 参数类型 和 返回类型

(() => 
        interface SearchFunc 
            (source: string, subString: string): boolean
        

        const mySearch: SearchFunc = function (source: string, sub: string): boolean 
            return source.search(sub) > -1
        

        console.log(mySearch(\'lczmx\', \'mx\'))
    
)()

类类型

TypeScript 也能够用它来明确的强制一个类去符合某种契约。

  • 一个类可以实现多个接口
  • 一个接口可以继承多个接口

一般使用

(() => 
        // 定义接口
        interface Alarm 
            alert(): any;
        

        // 定义类
        class Car implements Alarm 
            alert() 
                console.log(\'Car alert\');
            
        

    
)()

多个接口

(() => 
        // 定义接口
        interface Alarm 
            alert(): any;
        

        interface Light 
            lightOn(): void;

            lightOff(): void;
        

        // 定义类
        class Car2 implements Alarm, Light 
            alert() 
                console.log(\'Car alert\');
            

            lightOn() 
                console.log(\'Car light on\');
            

            lightOff() 
                console.log(\'Car light off\');
            
        

    
)()

接口继承

(() => 
        // 定义接口
        interface Alarm 
            alert(): any;
        

        interface Light 
            lightOn(): void;

            lightOff(): void;
        

        // 继承两个接口
        interface LightAlarm extends Alarm, Light 
            test(): void;

        

        // 定义类
        class Car implements LightAlarm 
            alert() 
                console.log(\'Car alert\');
            

            lightOn() 
                console.log(\'Car light on\');
            

            lightOff() 
                console.log(\'Car light off\');
            

            test() 
                console.log("test func")
            
        

    
)()

从ES6开始, 我们可以使用基于类的面向对象的方式, 在ts中, 我们可以使用一些特性,并且编译后的JavaScript可以在所有主流浏览器和平台上运行,而不需要等到下个JavaScript版本

一般使用

一般来说有三部分组成: 声明属性 定义构造方法 定义一般方法

(() => 
    class Greeter 
        // 声明属性
        message: string

        // 定义构造方法
        constructor(message: string) 
            // 初始化属性
            this.message = message
        

        // 定义一般方法
        greet(): string 
            return `hello $this.message`
        
    

    // 创建实例
    const greeter = new Greeter("lczmx")
    // 调用方法
    console.log(greeter.greet())
    // hello lczmx
)()

继承

这是面向对象的特性之一, 使用extends指定要继承的类

Dog继承Animal

(() => 
    class Animal 
        name: string

        constructor(name) 
            this.name = name
        
    

    // 继承Animal
    class Dog extends Animal 
        say(message: string): void 
            console.log(`$this.name: $message`)
        
    

    const dog = new Dog("小黄")
    // 调用say方法
    dog.say("汪汪汪~")

)()

和其他的面向对象的语言一样, 可以使用 "多态", 重写父类的方法即可

修饰符

类似封装

公共修饰符 public

使用public指定, 指的是可以让外部访问

默认都为public

举个例子:

(() => 
    class Animal 
        name: string
        public note: string

        constructor(name, note) 
            this.name = name
            this.note = note
        
    

    // 继承Animal
    class Dog extends Animal 

        public say(message: string): void 
            console.log(`$this.name: $message`)
        
    

    const dog = new Dog("小黄", "宠物")
    // 访问public属性
    console.log(dog.note)
    dog.say("汪汪汪~")

)()

私有修饰符 private

public相对于, 指的是不能被外部访问, 包括子类也不能被访问

(() => 
    class Animal 
        name: string
        private note: string

        constructor(name, note) 
            this.name = name
            this.note = note
        
    

    // 继承Animal
    class Dog extends Animal 

        private say(message: string): void 
            console.log(`$this.name: $message`)
        
    

    const dog = new Dog("小黄", "宠物")
    // 访问私有属性会报错
    // 以下两行都会报错
    console.log(dog.note)   // error
    dog.say("汪汪汪~")     // error

)()

受保护修饰符 protected

protected修饰符与private相似, 但protected成员在子类中仍然可以访问

(() => 
    class Animal 
        protected name: string

        constructor(name) 
            this.name = name
        
    

    // 继承Animal
    class Dog extends Animal 

        say(message: string): void 
            // 可以访问 name属性
            console.log(`$this.name: $message`)
        
    

    const dog = new Dog("小黄")
    dog.say("汪汪汪~")
    dog.name // error 不能访问

)()

只读修饰符 readonly

你可以使用readonly关键字将属性设置为只读的
只读属性必须在声明时或构造函数里被初始化

(() => 
    class Dog 
        readonly name: string

        constructor(name) 
            this.name = name
        

        say(message: string): void 
            // error
            // 修改只读属性
            this.name = "老黄"
            console.log(`$this.name: $message`)
        
    

    const dog = new Dog("小黄")
    dog.say("汪汪汪~")

)()

在构造时指定修饰符

我们可以在构造函数中指定对于的修饰符, 而不需要特意去声明属性

(() => 
    class Dog 
        constructor(protected name: string) 
            this.name = name
        

        say(message: string): void 
            console.log(`$this.name: $message`)
        
    

    const dog = new Dog("小黄")
    dog.say("汪汪汪~")

)()

读取器

TS中, 我们可以通过getters/setters来截取对对象成员的访问, 从而控制对对象的成员的访问

写起来和方法一样

(() => 
    class Person 
        firstName: string
        lastName: string

        constructor(firstName: string, lastName: string) 
            this.firstName = firstName
            this.lastName = lastName
        

        // 定义存取器
        // 获取时访问这个
        get fullName(): string 
            return `$this.firstName $this.lastName`
        

        // 设置时访问这个
        set fullName(value) 
            const names = value.split(\' \')

            this.firstName = names[0]
            this.lastName = names[1]
            console.log("change firstName lastName")
        
    
    // 使用
    const person = new Person("张", "三")

    console.log(person.fullName)  // 触发 get
    person.fullName = "李 四"     // 触发 set
    console.log(person.fullName)  // 触发 get
)()

静态属性

静态属性即是存在于类本身上面而不是类的实例上的属性

(() => 
    class Person 
        name1: string = \'A\'
        static name2: string = \'B\'
    

    // 在类中访问
    console.log(Person.name2)
    // 使用实例不能访问name2, 可以访问name1
    const person = new Person()
    console.log(person.name1)
)()

抽象类

抽象类做为其它派生类的基类使用。 它们不能被实例化
使用abstract定义抽象类和在抽象类内部定义抽象方法

(() => 
    abstract class Animal 
        abstract cry()

        run() 
            console.log(\'execute run()\')
        
    

    class Dog extends Animal 
        cry() 
            console.log(\'execute Dog cry()\')
        
    

    const dog = new Dog()
    dog.cry()
    dog.run()
)()

函数

ts的函数为js的函数添加了额外的功能, 更加有利于函数的使用

一般使用

大体和JavaScript中那样使用

(() => 
    // 有名称的函数
    function add(x, y) 
        return x + y
    

    // 匿名函数
    let myAdd = function (x, y) 
        return x + y
    
    console.log(add(1, 2))
    console.log(myAdd(3, 4))

)()

使用类型注解

可以注解参数和返回值

(() => 
    function add(x: number, y: number): number 
        return x + y
    

    let myAdd = function (x: number, y: number): number 
        return x + y
    
    console.log(add(1, 2))
    console.log(myAdd(3, 4))

    let myAdd2: (x: number, y: number) => number =
        function (x: number, y: number): number 
            return x + y
        
)()

可选参数和默认参数

在ts中, 每个函数的参数默认都是必需的, 即不能多传也不能少传
在某些场景中, 我们需要参数是可选的或默认的

(() => 
    function fullName(firstName: string = \'lcz\', lastName?: string): string 
        if (lastName) 
            return firstName + lastName
         else 
            console.log(firstName, lastName)    // lcz undefined
            return firstName
        
    

    console.log(fullName())
    console.log(fullName("lcz", "mx"))
)()

可选参数: ?:, 不传值时, 值为undefined

剩余参数

可以将多余的参数作为一个数组, 类似python的*args

(() => 
    function info(x: string, ...args: string[]) 
        console.log(`x: $x  args: $args`)
    

    info("a", "b", "c", "d", "e", "f")

)()

函数重载

函数重载主要是解决两个问题: 参数类型不一样、参数个数不一样, 为此需要定义多个函数

(() => 
    // 重载函数声明
    function add(x: string, y: string): string
    function add(x: number, y: number): number

    // 定义函数实现
    function add(x: string | number, y: string | number): string | number 
        // 在实现上我们要注意严格判断两个参数的类型是否相等,而不能简单的写一个 x + y
        if (typeof x === \'string\' && typeof y === \'string\') 
            return x + y
         else if (typeof x === \'number\' && typeof y === \'number\') 
            return x + y
        
    

    console.log(add(1, 2))
    console.log(add(\'a\', \'b\'))
    // console.log(add(1, \'a\')) // error

)()

泛型

泛型指的是在定义函数、接口或类的时候, 不预先指定具体的类型, 而在使用的时候再指定具体类型的一种特性
如下面这个例子:

(() => 
    function f<T>(a: T) 
        console.log(typeof a)
    

    f<number>(1)    // number
    f<string>("abc")    // string
    f<number[]>([1, 2, 3]) // object
)()

使用<>指定类型, 在使用的时候也可以用<>指定具体的类型

一般使用

(() => 
    function createArray<T>(value: T, count: number) 
        const arr: Array<T> = []
        for (let index = 0; index < count; index++) 
            arr.push(value)
        
        return arr
    

    const arr1 = createArray<number>(11, 3)
    console.log(arr1[0].toFixed())
    // console.log(arr3[0].split(\'\')) // error

    const arr2 = createArray<string>(\'aa\', 3)
    console.log(arr2[0].split(\'\'))
    // console.log(arr4[0].toFixed()) // error

)()

多个泛型参数

我们可以在一个函数中定义多个泛型参数

(() => 
    function swap<K, V>(a: K, b: V): [K, V] 
        return [a, b]
    

    const result = swap<string, number>(\'abc\', 123)
    console.log(result[0].length, result[1].toFixed())  // 3 \'123\'

)()

泛型接口

我们可以在定义接口时, 为接口中的属性或方法定义泛型类型
在使用接口时, 再指定具体的泛型类型

(() => 
    // UserCRUD 接口
    interface IUserInfo<T> 
        data: T[]
        add: (t: T) => void
        getById: (id: number) => T
    

    // 存放用户数据
    class UserInfo 
        id?: number; //id主键自增
        name: string; //姓名
        age: number; //年龄

        constructor(name, age) 
            this.name = name
            this.age = age
        
    

    // 操作用户
    class UserCRUD implements IUserInfo <UserInfo> 
        data: UserInfo[] = []

        add(user: UserInfo): void 
            user = ...user, id: Date.now()
            this.data.push(user)
            console.log(\'保存user\', user.id)
        

        getById(id: number): UserInfo 
            return this.data.find(item => item.id === id)
        
    


    const userCRUD = new UserCRUD()
    userCRUD.add(new UserInfo(\'tom\', 12))
    userCRUD.add(new UserInfo(\'tom2\', 13))
    
    console.log(userCRUD.data)
)()

泛型类

在定义类时, 为类中的属性或方法定义泛型类型
在创建类的实例时, 再指定特定的泛型类型

(() => 
    class GenericNumber<T> 
        zeroValue: T
        add: (x: T, y: T) => T
    

    let myGenericNumber = new GenericNumber<number>()
    myGenericNumber.zeroValue = 0
    myGenericNumber.add = function (x, y) 
        return x + y
    

    let myGenericString = new GenericNumber<string>()
    myGenericString.zeroValue = \'abc\'
    myGenericString.add = function (x, y) 
        return x + y
    

    console.log(myGenericString.add(myGenericString.zeroValue, \'test\'))
    console.log(myGenericNumber.add(myGenericNumber.zeroValue, 12))
)()

泛型约束

如果我们直接对一个泛型参数取length属性, 会报错, 因为这个泛型根本就不知道它有这个属性

// 没有泛型约束
function fn <T>(x: T): void 
  // console.log(x.length)  // error

我们可以使用泛型约束来实现

interface Lengthwise 
  length: number;


// 指定泛型约束
function fn2 <T extends Lengthwise>(x: T): void 
  console.log(x.length)

我们需要传入符合约束类型的值,必须包含必须 length 属性:

fn2(\'abc\')
// fn2(123) // error  number没有length属性

其他

声明文件

在ts中, 假如我们需要用第三方库, 但在ts中不能用thml中的<script>标签, 那么我们应该如何引用呢?
很简单, 使用declare var定义, 例子:

declare var jQuery: (selector: string) => any;

jQuery(\'#foo\');

注意: 一般无需我们手动定义, 下载即可, 下载声明文件: npm install @types/jquery --save-dev

declare var并没有真的定义一个变量,只是定义了全局变量 jQuery 的类型,仅仅会用于编译时的检查,在编译结果中会被删除。它编译结果是:

jQuery(\'#foo\');

内置对象

JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型
内置对象是指根据标准在全局作用域(Global)上存在的对象
这里的标准是指 ECMAScript 和其他环境(比如 DOM)的标准

ECMAScript 的内置对象

  • Boolean
  • Number
  • String
  • Date
  • RegExp
  • Error
/* 1. ECMAScript 的内置对象 */
let b: Boolean = new Boolean(1)
let n: Number = new Number(true)
let s: String = new String(\'abc\')
let d: Date = new Date()
let r: RegExp = /^1/
let e: Error = new Error(\'error message\')
b = true
// let bb: boolean = new Boolean(2)  // error

BOM 和 DOM 的内置对象

  • Window
  • Document
  • HTMLElement
  • DocumentFragment
  • Event
  • NodeList
const div: HTMLElement = document.getElementById(\'test\')
const divs: NodeList = document.querySelectorAll(\'div\')
document.addEventListener(\'click\', (event: MouseEvent) => 
  console.dir(event.target)
)
const fragment: DocumentFragment = document.createDocumentFragment()

本文来自博客园,作者:403·Forbidden,转载请注明原文链接:https://www.cnblogs.com/lczmx/p/15708603.html

以上是关于初识TypeScript的主要内容,如果未能解决你的问题,请参考以下文章

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

typescript Angular 2测试片段。代码库https://developers.livechatinc.com/blog/category/programming/angular-2/

typescript Angular最终版本的Angular 2测试片段。代码库https://developers.livechatinc.com/blog/category/programming

typescript Angular最终版本的Angular 2测试片段。代码库https://developers.livechatinc.com/blog/category/programming

typescript Angular最终版本的Angular 2测试片段。代码库https://developers.livechatinc.com/blog/category/programming