JavaScript的超集, 拓展了JavaScript,并添加了类型
可以在任何支持Javascript的平台中执行,不能被js解析器直接执行, 需要编译转换(类比less, scss)
npm i -g typescript
全局安装ts编译器tsc xxx.ts
let a: number // 声明一个变量, 并指定它的类型为number
a = 10
a = ‘hello‘ // 会有红线提示,不能将类型“string”分配给类型“number”。
// 声明并定义
let b : number = 1
b = true
// 实际上声明和赋值是同时进行的, ts可以自动对变量进行类型检测
let c = true
c = 1
// 为什么还要主动定义呢? 主要是函数的参数和返回类型
function sum (a: number, b: number): number{ // 括号后面的冒号表示返回的类型
return a + b
}
sum(123, ‘456‘) // 第二个类型不符合会报错
sum(123, 456, 789) // 如果是js, 多传参并不会报错, 但js更严格, 不允许多传参
// 虽然报错了, 但还是会编译成js, 只是会在编译时报错, 如果想报错不编译, 需要配置
// 也可以用字面量进行类型声明
let gender : ‘man‘ | ‘woman‘ | 0 | 1
gender = ‘man‘
gender = 0
gender = ‘女‘ // 限定变量在某几个值之间
let d : string | number
d = true
any : 任意类型, 对该变量关闭ts检测(尽量不用)
// 1显式声明
let e: any
e = 10
e = true
// 2. 隐式声明
let f // 声明变量如果不赋值, ts解析器就会自动当成any
f = 10
f = true
unkonwn: 未知类型
和any有什么区别:
? any可以赋值给任意变量(不仅影响自己, 还影响别人 )
? unknow不能直接赋值给其他变量
? unknow实际上就是一个类型安全 的any,
let s1 : any
s1 = 123
let s2 : string
s2 = s1 // any可以赋值给任意变量, 这里不会报错
let s3 : unknown
s3 = 123
let s4 : string
s4 = s3 // unknow会报错
// unkown要怎么赋值给其他变量呢
// 方法1:先做类型判断
if(typeof s3 === ‘string‘){
s4 = s3
}
// 方法2: 类型断言, 用来告诉解析器变量的实际类型
/*
* 语法: 变量 as 类型
* <类型> 变量
**/
s4 = s3 as string
s4 = <string>s3
void: 为空, 主要用在函数的返回值, 没有返回值
never: 永远不会返回结果, 连undefind都不返回, 比如用来捕获异常的函数, 直接就抛出了
object
let a:object //并不这么用, 因为js里数组对象函数都是对象
a = {}
a = function () {}
let b : {name:string, age?:number, [propName:string]:any}
// 一般指定对象包含的属性
// 语法: {属性名: 属性值类型, ...}
// 属性名后面的问号表示是可选的
// [propName:string]:any 表示任意类型的属性, 就是说后面不做限制, 可以有多个属性, 属性值类型任意
b = {}
b = {name : ‘abc‘}
// 定义函数的类型声明
// 类似箭头函数的结构
// 语法: (形参:类型, 形参:类型,...)=> 返回值类型
let c : (a: number, b:number)=>number
array
// 用来表示数组里存放什么类型的数据
let a : string[]
let b : <number>[]
tuple: ts新增的类型, 元组
, 固定长度的数组
let a : [string , string] // 长度固定, 效率更好
a = [‘hello‘, ‘word‘]
enum: ts新增的类型, 枚举
enum Gender {
woman = 0,
man = 1
}
let g : {name:string, gender:Gender}
g = {
name: ‘张三‘,
gender:Gender.man
}
console.log(g.gender === Gender.man)
// 把可能出现的列出来
|
表示或, &
表示且
let j : {name: string} & {age: number}
j = {name: ‘张三‘, age: 18}
类型的别名
type myType = 1 | 2 | 3 | 4 | 5
let a : myType
let b : myType
自动编译
监控单个文件 tsc xxx.ts -w
*
监控整个项目
要有相关配置文件tsconfig.json
, 可以用tsc -- init
生成
配置文件里只要一对大括号, 就能生效
tsc
配置选项
include: 定义希望被编译文件所在的目录
"include": [
"./src/**/*"
]
// 两个星号表示任意目录, 一个星号表示任意文件
exclude: 排除目录
extends: 继承的配置文件
files: 指定被编译的文件列表, 只有需要编译的文件少时才会用到
compilerOptions: 编译器的选项 (技巧, 写个错的, 报错信息会显示哪些可选项)
"target": "es2015"
es版本
"module": "es2015"
使用的模块化规范
// "lib":[]
项目使用的库, 一般不改
"outDir": "./dist"
编译后输出的目录
"outFile": "./dist/app.js"
将全局作用域的代码合并到一个文件
"allowJs": false
是否对js文件进行编译, 默认false
"checkJs": false
检查js是否符合规范 , 默认是false
"removeComments": false
是否移除注释
"noEmit": false
只检查语法, 不生成编译后的文件
"noEmitOnError": false
有错误时不生成编译后的文件
"strict": true
所有的严格检查开关, 建议打开
"alwaysStrict": false
编译后的文件是否使用js严格模式
当使用import
, export
时, 自动进入严格模式 , js中不会再生成"use strict"
"noImplicitAny": true
不允许隐式any
类型
"noImpliciThis": true
不允许不明确类型的this,
function fn1(){
console.log(this) //这里的this是不明确的, 不能确定谁会调用它
}
// 如果只想让能明确的对象来调用它, 怎么解决
function fn1(this: window){
console.log(this)
}
"strictNullChecks": true
严格的检查空值
let box = documnet.getElementById(‘box‘)
box.addEventListener(type: ‘click‘, listener: function(){
alert(‘hello‘)
})
// 这里的box可能拿不到, 后面的绑定事件就会出错
// 配置了严格检查空值, 这里就会有提示
// 怎么解决
let box = documnet.getElementById(‘box‘)
if(box !== null){
box.addEventListener(type: ‘click‘, listener: function(){
alert(‘hello‘)
})
}
// 另一种写法
box?.addEventListener(type: ‘click‘, listener: function(){
alert(‘hello‘)
})
npm init -y
生成package.json
npm i -D webpack webpack-cli typescript ts-loader
安装包
新建webpack.config.js
const path = require(‘path‘)
// webpack中的所有信息都写在这里
module.exports = {
// 指定入口文件
entry: "./src/index.ts",
//指定打包文件的左右目录
output: {
// 制定打包文件的目录
path: path.resolve(__dirname, ‘dist‘),
// 打包后文件的文件名
filename: "bundle.js"
},
// 指定webpack打包时要使用的模块
module: {
// 指定要加载的规则
rules: [
{
// test指定的是规则生效的文件
test: /\.ts$/,
// 使用loader
use: ‘ts-loader‘,
// 排除的文件
exclude: /node-modules/
}
]
}
}
新建tsconfig.json
{
// 随便配置下
"compilerOptions": {
"module": "ES2015",
"target": "ES2015",
"strict": true
}
}
package.json
新增
{
// ...
"scripts": {
// ...
,
"build": "webpack"
}
// ...
}
执行npm run build
进行打包
其他webpack知识点补充:
自动输出html文件
安装插件, npm i -D html-webpack-plugin
在src
下新建index.html
模板
配置webpack.config.js
文件
// ...
const htmlWebpackPlugin = require(‘html-webpack-plugin‘)
//...
module.exports = {
//...
// webpack插件配置
plugins: [
new htmlWebpackPlugin(
{
template: "./src/index.html"
}
)
]
}
监控变化并重新生成
安装插件, npm i -D webpack-dev-server
配置package.json
// ...
"scripts": {
// ...
,
"start": "webpack serve --open chrome.exe"
}
// ...
运行npm run start
每次打包前先清空dist目录
安装插件npm i -D clean-webpack-plugin
配置webpack.config.js
文件
// ...
const {cleanWebpackPlugin} = require(‘clean-webpack-plugin‘)
//...
module.exports = {
//...
// webpack插件配置
plugins: [
new cleanWebpackPlugin(),
new htmlWebpackPlugin(
{
template: "./src/index.html"
}
)
]
}
设置哪些文件可以当成模块来引用
配置webpack.config.js
文件
?```js
// ...
module.exports = {
// 设置引用模块
resolve: {
extensions:[‘.ts‘, ‘.js‘] // 这样设置后, ts里就可以引用ts
}
}
?```
打包后的js的语法兼容: 使用babel , 结合webpack一起使用
安装依赖 npm i -D @babel/core @babel/preset-env babel-loader core-js
配置webpack.config.js
文件
module: {
// 指定要加载的规则
rules: [
{
// test指定的是规则生效的文件
test: /\.ts$/,
// 使用loader, 这里要注意: loader的执行顺序是从下往上的
use: [
// 配置babel
{
// 指定加载器
loader: ‘babel-loader‘,
// 配置项
options: {
// 设置预定义环境
presets:[
[
// 指定环境的插件
"@babel/preset-env",
// 配置信息
{
// 要兼容的浏览器
targets: {
"chrome": "58",
"ie": "11" // 设置了兼容ie,es6就转成旧写法了
},
// 指定corejs的版本
"corejs":"3",
// 使用corejs的方式, usage按需加载
"useBuiltIns": "usage"
}
]
]
}
},
‘ts-loader‘
],
// 排除的文件
exclude: /node-modules/
}
]
},
webpack打包不使用箭头函数(兼容ie)
// ...
output: {
//...
environment: {
// 告诉webpack不使用箭头函数
arrowFunction: false
}
}
//...
上面的都和js一样, 下面的抽象类和接口是ts独有的, 编译成js就没了
父类不想被实例
// 抽象类: 不能用来创建对象, 就是专门用来被继承的父类
// 在class前面加上abstrat
abstract class Animal {
name:string
age:number
constructor(name:string, age:number){
this.name = name
this.age = age
}
// 抽象方法: 定义在抽象类中, 只是表示了有这个方法, 必须在子类中进行重写
//在方法名前加 abstract , 没有方法体
abstract say():void
}
class Dog extends Animal {}
对类的结构做限制, 但不设置具体值
(function (){
// 定义一个对象的类型
type myType = {
name: string,
age: number
}
const obj:myType = {
name: ‘张三‘,
age: 18
}
/**
* 接口就是用来定义一个类的结构, 应该包含那些属性和方法
* 接口就是对类的限制
* 也可以当成类型声明使用
*/
// 1. 当成类型生明使用
interface myInterFace{
name: string
age: number
}
interface myInterFace{
height: number
}
//再定义一个同样名字的接口, 在ts里是合法的, 实际是两个合并
const obj2: myInterFace = {
name: ‘李四‘,
age: 19,
height: 180
}
// 2. 定义类的结构
// 接口中的属性都不能有实际的值
// 接口只是定义了对象的结构,而不考虑实际值
interface myInter {
name:string
say():void // 接口中的方法都时抽象方法
}
// 类实现接口, 用implements
class myClass implements myInter{
name: string
constructor(name: string){
this.name = name
}
say (){
console.log(‘123‘);
}
}
const myclass = new myClass(‘王五‘)
console.log(myclass.name);
myclass.say()
})()
如果不想让属性被任意修改, 可以添加private 设置私有属性, 类内部添加get, set存取器修改
// 实例属性在实例中是可以被任意修改的, 如果不想被修改? 或者要按照我的方法来修改
// 添加private 设置私有属性, 类内部添加修改方法
// tsconfig.json 中添加 "noEmitOnError":true, 错误时不编译
(function(){
class Person{
/**
* TS可以在属性前面添加修饰符, 比如之前的static
* public 表示公共属性, 默认添加
* private 表示私有属性, 只能在类内部访问(修改)
* protected 表示受保护的类, 只能在当前类和当前类的子类中访问
* 可以通过类内部的方法间接修改
*/
private _name:string
private _age: number
constructor(name:string, age:number){
this._name = name
this._age = age
}
setName(value:string){
this._name = value
}
setAge(value: number){
if(value > 0 && value <150){
// 在内部的方法添加了限制, 只有符合设置规则的修改才允许
this._age = value
}
}
/**
* getter方法用来读取属性, setter方法用来设置属性, 它们被称为属性的存取器
* TS中提供了更方便写法 set get
* 用的时候当成属性来用
*/
get name():string{
return this._name // get访问器不能有参数, 必须用return返回
}
set name(value:string){
this._name = value // set访问器必须有参数, 不能有return
}
}
const per = new Person("张三", 18)
console.log(per);
//per._name = "李四" // 报错了, 私有属性只能在类内部修改
per.setName(‘李四‘)
console.log(per)
per.setAge(-1) // 不符合规则, 不让修改
console.log(per)
console.log(per.name); // 直接调用了set访问器
per.name = "王五" // set访问器, 和属性一样的赋值, 而不是方法传参
console.log(per.name);
})()
可以直接将属性定义在构造函数中
class A {
constructor(public name:string, public age:number){}
}
// 相当于
class A{
name: string
age: number
constructor(name: string,age: number){}
}
(function (){
// 定义函数或者类的时候, 如果类型不明确可以使用泛型
// 和any的区别, any是关闭了检查, 泛型是一个占位模板
function fn <T> (a:T) :T{
return a
}
console.log(fn(123))
console.log(fn(‘456‘))
// 泛型可以设置多个
function fn2 <T, K> (a:T, b: K) :T{
console.log(b)
return a
}
let b = fn2(789, ‘abc‘)
console.log(b);
// 泛型可以主动指定
fn2<string, number>(‘qwe‘, 996)
// 泛型继承接口, 就是说类型必须符合接口的格式
interface Inter{
length: number
}
function fn3<T extends Inter>(a:T) {
return a.length // 类型和接口一样, 有lenght属性
}
})()
less解析npm i -D less less-loader css-loader style-loader
css兼容加载器 npm i -D postcss postcss-loader postcss-preset-env
原文:https://www.cnblogs.com/jiutianzhiyu/p/14705861.html