初识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
的语法:
最后编译ts
为js
, 再次引用:
$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自动编译
- 执行命令, 生成
tsconfig.json
文件$tsc --init
- 修改配置
主要修改:"outDir": "./js", /* 把编译后的文件放到js目录下 */ "strict": false, /* 不使用严格模式 */
- 启动监听任务
$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.json
和tsconfig.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
打包htmlclean-webpack-plugin
清除打包过程中的目录ts-loader
ts编译工具cross-env
跨平台命令支持
创建文件
文件目录结构:
├─build
├─public
└─src
- 入口JS:
src/main.ts
document.write(\'Hello Webpack TS!\')
- index页面:
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>webpack & TS</title>
</head>
<body>
</body>
</html>
- 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
基础类型
布尔值
即true
或false
(() =>
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
中, undefined
和null
两者各自有自己的类型分别叫做undefined
和null
它们的本身的类型用处不是很大:
(() =>
let a: null = null
let b: undefined = undefined
let name: string = null
name = "lczmx"
console.log(`username: $name`)
)()
默认情况下
null
和undefined
是所有类型的子类型, 就是说你可以把null
和undefined
赋值给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
类型的变量没有什么大用, 因为你只能为它赋予undefined
和null
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