1、安装编译软件让其支持typescript
1-1、安装 typescript
npm install -g typescript 或: yarn global add typescript
1-2、创建文件夹,在vscode中输入
tsc --init
1-3、配置输出文件
1-4、配置vscode终端监视typescript自动生成js
1-5 创建ts 文件即可实现
2、Ts 数据类型的定义
2-1 基本数据类型
// 定义字符串类型
let str:string = 'ts'
// 定义boolean类型
let falg:boolean = true
// 定义number类型
let num:number = 10
// 定义null
let isNull:null = null
// 定义undefined
let isUndefined:undefined = undefined
let num:number | undefined // 用于并未赋值的数值类型
// 定义any类型
let isAny:any = [] // 任意类型好比关闭了该变量的ts类型,使用js【常用于无法确定具体规定的类型,例如DOM节点的获取】
2-1-1 联合数据类型
只能访问此联合类型的所有类型里共有的属性或方法
联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型
// 定义联合类型
let params:string|number
// 只能访问此联合类型的所有类型里共有的属性或方法
function getLength(something: string | number): number {
return something.length; // 错误
}
2-1-2 类型别名【type】
type typeList = string | number | number[]
const b:typeList = [1,2,34,0]
2-1-3 常用内置对象定义
// 内置对象: 常用:【Date/RegExp/HTMLElement/NodeList/MouseEvent】
let date:Date = new Date()
let math:RegExp = /\s/g
const body: HTMLElement = document.body;
const divList: NodeList = document.querySelectorAll('div');
document.addEventListener('click', (e: MouseEvent) => {})
2-2 复合数据类型
2-2-1 数组定义
let arr:number[] = [1,25,6]
let arr2:Array<number> = [1,2,5]
let arr3:[string,number] = ['xxx',10] // 元祖类型
2-2-2 枚举类型
enum flag {color = 1 ,red = 2}
console.log(flag.color) // 1
console.log(flag[1]) // color
enum flag2 {color,red}
console.log(flag2.color) // 0
enum flag3 {color,red = 10,yellow,block = 11}
console.log(flag3.color,flag3.red,flag3.yellow,flag3.block,flag3[11]) // 0 10 11 11 block
// 原因:枚举类型的编译结果及输出的枚举结果
// 编译结果
var flag3;
(function (flag3) {
flag3[flag3["color"] = 0] = "color";
flag3[flag3["red"] = 10] = "red";
flag3[flag3["yellow"] = 11] = "yellow";
flag3[flag3["block"] = 11] = "block";
})(flag3 || (flag3 = {}));
console.log(flag3)
{
0: 'color',
10: 'red',
11: 'block',
color: 0,
red: 10,
yellow: 11,
block: 11
}
2-2-3 void 类型
// 用于定义函数无返回值
function run():void{
console.log('void类型')
}
// !!! 错误写法
function run():undefined{
console.log('void类型')
}
3、Ts 函数的定义
3-1-1、规定参数类型【必传】
function funTs(name:string,age:number):string{ // 定义函数的参数类型和返回值类型
return name + age
}
funTs('n')【错误】 // 以上方法定义的参数在ts中参数都为必传且符合规定类型
3-1-2、可选参数【只能配置在参数末尾】
function funTs(name:string,age?:number):string{ // 定义函数的参数类型和返回值类型
return name + age
}
funTs('xx') // 正确
3-1-3、默认参数
function funTs(name:string = '小明',age:number):string{ // 定义函数的参数类型和返回值类型
return name + age
}
funTs('xx',10) // 正确
3-1-4、剩余参数
function funTs(name:string = '小明',age:number,...rest:number[]):string{ // 定义函数的参数类型和返回值类型
return name + age
}
funTs('xx',10,10,345) // 正确
3-1-5、函数的重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。
// 不使用函数重置,该函数返回值类型是仍然是 : string | number
function get(params:string | number):string | number { // 儿子一和儿子二商量着来,父亲无法确定谁来照顾他
if(params) {
return 10
}
return 'xxx'
}
let result1:string = get('xxx') // 错误
let result2:number = get (10) // 错误
// 使用函数重载可以确定函数唯一返回值类型
function get2(params:string):string // 儿子一为 String
function get2(params:number):number // 儿子二为 number
function get2(params:string | number):string | number { // 父亲可以确定哪个儿子来照顾他
if(params) {
return 10
}
return 'xxx'
}
let res1:string = get2('xxxx')
let res2:number = get2(10)
4.interface【接口】
使用接口(Interfaces)来定义对象的类型
接口好比一个模具提前规定了某些对象的样子(属性特征),所以赋值的时候,变量的形状必须和接口的形状保持一致。
// 基本语法
interfaces 接口名 {
接口的定义
}
// 基本使用
// 定义 userInfo 的接口类型
interface IUserInfo {
age:number,
like?:Array<string>
}
// 定义 queryParams 的接口类型
interface IQueryParams {
userId:number,
userName:string,
userInfo:IUserInfo,
}
// 使用接口
let formData:IQueryParams = {
userId:10,
userName:'person',
userInfo:{
age:20,
like:['电影']
}
}
4-1-1 定义接口任意属性和只读属性【readonly】
一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候
interface IUserInfo {
name:string,
age:number,
}
const obj:IUserInfo = {
name:'xx',
age:10,
score:10, // 错误
}
// 定义任意类型【】
interface IUserInfo {
name:string,
age:number,
[attribute:string]:string | number, // 任意属性的类型是接口确定属性类型的集合,一般设置成 any 类型
}
const obj:IUserInfo = {
name:'xx',
age:10,
score:10,
class:'一'
}
// 定义任意类型方法二【无需在接口中设置任意类型】
interface IUserInfo {
name:string,
age:number,
}
let score:string = 'test'
const obj:IUserInfo = {
name:'xx',
age:10,
[score]:[1,2131]
}
// 定义任意属性
interface IUserInfo {
readonly name:string,
age:number,
}
const obj:IUserInfo = {
name:'yellow',
age:20
}
obj.name = 'xxx' // 错误【不可修改改属性值】
4-1-2 利用接口定义函数的形状
// 定义函数模型【函数参数1 为 string 类型 参数2 为 string 返回值为 string】
interface IFunDesc {
(name:string,color:string):string
}
// getIfo 使用定义的函数模型
let getInfo:IFunDesc
// 根据模型创建函数
getInfo = (params:string,params2:string):string => {
return params + params2
}
4-1-3 接口的继承
interface IMac {
color:string,
}
interface IMacBook extends IMac {
get(params:string):void
}
const a:IMacBook = {
color:'red',
get(params:string){
console.log(params)
}
}
a.get('xxxx')
a.color
4-1-4 类类型接口【implements】
interface IPerson { // 规定使用该接口的类必须用接口中的方法和属性
name:string,
age:number,
say(context:string):void
}
class Person implements IPerson { // implements 使用 类接口
name:string
age:number
constructor(name:string,age:number){
this.name = name
this.age = age
}
say(context:string){
console.log(context)
}
}
5. class
5-1-1 实现类的简单继承
继承必要条件:父子都要有constructor构造器(父类不写默认条件),子类必须写constructor构造器且使用 super() 方法借用父类的属性。【此处指的都是公有方法和属性】
class Person {
name:string = '父类'
constructor(){ // 每次实例化对象其实就是调当前constructor方法
}
}
class Son extends Person {
constructor(){
super() // super 相当于当前类的父类(父类的constructor方法)
}
say(){
console.log(`访问父类的:${this.name}`)
}
}
const Baba = new Person()
console.log(Baba.name) // 父亲
const a = new Son()
a.say() // 访问父类的:父亲
// 使用 abstract 关键字 实现抽象类和方法【不能被实例的类】
abstract class Person {
public age:number | undefined
constructor(age:number){
this.age = age
}
abstract say():void
}
5-1-2 设置公有属性【public】【父类、子类、子类和父类实例对象都可访问】
class Person {
public name:string = '父类' // 公有属性public 可省略
}
class Son extends Person {
constructor(){
super()
}
say(){
console.log(`访问父类的:${this.name}`)
}
}
const Baba = new Person()
console.log(Baba.name) // 父亲
const a = new Son()
a.say() // 访问父类的:父亲
5-1-3 设置保护类属性【protected】【父类、子类中可以访问】
class Person {
protected name:string = '父类'
}
class Son extends Person {
constructor(){
super()
}
say(){
console.log(`访问父类的:${this.name}`)
}
}
const Baba = new Person()
console.log(Baba.name) // 不可访问
const a = new Son()
a.say() // 访问父类的:父亲【子类方法中,在子类中访问父类属性】
5-1-4 设置私有属性【private】 【只有父类中可以访问】
class Person {
private name:string = '父类'
say(){
console.log('父类:',this.name)
}
}
class Son extends Person {
constructor(){
super()
}
say(){
console.log(`访问父类的:${this.name}`) // 报错,不可访问父类的属性
}
}
console.log(Person.name) // 父亲
const Baba = new Person()
console.log(Baba.name) // 不可访问
Baba.say() // 父类:父亲 【父类方法中访问父类的属性】
5-1-5 设置静态方法【static】
class Person {
static say(){
console.log('父类:',this.name)
}
}
class Son extends Person {
constructor(){
super()
}
}
Person.say() // 可以访问
const a = new Person()
a.say() // 不可访问
6.元祖
数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。可以让数组设置不同的item类型
let arr:[string,number] = ['xxx',10]
arr.push('sstr') // 可以越界添加元素,但是类型是其元祖类型中类型的复合
7.泛型
是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。相当与对any类型的升级版,它会根据用户输入的具体类型来进行断言【解决类、函数、方法的复用性并且兼容不定类型的数据】
7-1-1 函数中泛型的使用
T 是类型变量[可以使用任何字母代替,常用 T/U ],它是一种特殊的变量,只用于表示类型而不是值,使用 <> 定义。定义了类型变量之后,你在函数中任何需要指定类型的地方使用 T 都代表这一种类型,这样也能保证返回值的类型与传入参数的类型是相同的了。
// 不适用泛型时的书写方法
function get(params:string):string
function get(params:number):number
function get(params:string | number):string | number | undefined{
if(params as string) {
return 'xxx'
}else if(params as number) {
return 6666
}
}
get('xxx')
get(10)
// 使用泛型
function get<T>(params:T):T{
return params
}
get<number>(10)
get<string>('xxx')
7-1-2 泛型接口
interface IParams<T>{ // 定义泛型参数为 T
name:string,
age:number,
test:T
}
const obj:IParams<string>= { // 使用泛型时要给定其泛型参数类型
name:'xxx',
age:10,
test:'xxxx'
}
// 方法一
interface IPer<T> {
(params:T):T
}
let result:IPer<string> = function getReust<T>(params:T):T{
return params
}
result('xxxx')
// 方法二
let result2:IPer<number> = <T>(params:T):T => params
result2(10)
// 方法三
let result3 = <T>(params:T) => params
result3<number>(20)
7-1-3 泛型的约束【约束好泛型拥有的属性】
const resulut = <T>(params:T) => params.length // 类型“T”上不存在属性“length”【报错】
// 泛型的约束
interface Ileng { // 约定泛型可拥有的属性
length:number
}
const resulut = <T extends Ileng>(params:T) => params.length
7-1-4 类泛型使用
class Per<T>{
params:T
constructor(params:T){
this.params = params
}
}
const a = new Per<number>(10)
const a2 = new Per<string>('xxx')
7-1-5 类型泛型和接口的使用
class Handler<T>{
say(params:T):T{
return params
}
}
interface Ipara {
name:string
}
const a = new Handler<Ipara>()
a.say({name:'xxcvxv'})
a.say({name:10}) // 错误
========================================
class Handler<T>{
name:string
constructor(params:string){
this.name = params
}
say(params:T):T{
return params
}
}
interface Ipara {
name:string
}
const a = new Handler<Ipara>('熊')
a.say({name:'xxcvxv'}) // 'xxcvxv'
a.name // '熊'
a.say({name:10}) // 错误
8.命名空间【namespace】
开启一块属于自己的私人空间,开启命名空间,外部要用改空间中的数据,需要利用export 暴露
// 共公模块
export namespace Project { // 命名空间1
export interface IObj {
name:string
}
}
export namespace Project2 { // 命名空间2
export interface IObj {
age:number
}
}
// 使用模块
import {Project,Project2} from './a'
let obj:Project.IObj = {
name:'xxx'
}
let obj2:Project2.IObj = {
age:10
}
9. 装饰器
本质是一个方法,可以为类、方法、属性进行扩展,不能修改当前的类。
9-1-1类修饰器
// 不修改改变当前类,只能在其当前类的prototype上添加属性或方法
// =================== 一般修饰器 =============================
function PerSonDec(target:any){ // 收到当前被修式的类
target.prototype.color = 'xxx'
target.prototype.run = function () {
console.log('run')
}
}
@PerSonDec // 被修饰的类前书写 @修饰器名称
class Person {
public age:number | undefined
constructor(age:number){
this.age = age
}
say(){
}
}
const son = new Person(200)
console.log(son)
// Person {age: 200}
// age: 200
// [[Prototype]]: Object
// color: "xxx"
// run: ƒ ()
// constructor: class Person
// say: ƒ say()
// [[Prototype]]: Object
// ================= 工厂方式装饰器【看动态传参】 ========================
function PerSonDec(color:string){
return function(target:any){
target.prototype.color = color
}
}
@PerSonDec('red') // 被修饰的类前书写 @修饰器名称
class Person {
public age:number | undefined
constructor(age:number){
this.age = age
}
say(){
}
}
9-1-2 修饰器实现对当前类的重载
function PerSonDec(target:any){
return class newPersonClass extends target {
age:number = 200
say(){
}
}
}
@PerSonDec
class Person {
public age:number | undefined
constructor(age:number){
this.age = age
}
say(){
}
}
const son = new Person(200)
console.log(son)
9-1-3 类的属性装饰器
function PerSonAttrDec(params:string){
return function(target:any,attr:any){ // target: 当前类的 prototype , arrt : 被修饰的属性
target[attr] = '原型对象上的属性'
}
}
class Person {
@PerSonAttrDec('xxx')
age:number = 20
constructor(){
}
say(){
}
}
const son = new Person()
console.log(Person.prototype.age) // 原型对象上的属性
console.log(son.age)//20
9-1-4 类的方法修饰器
function PerSonFunDec(params:string){
return function(target:any,funName:string,dec:any){ // target: 当前类的显示原型对象 funName : 被修饰的方法名 dec:修饰器对修
console.log(dec.value) // 当前被修饰的方法
dec.value = function(){
console.log('修饰器修改了我')
}
}
}
class Person {
age:number = 20
constructor(){
}
@PerSonFunDec('xxx')
say(){
console.log('wo')
}
}
const son = new Person()
son.say() // 修饰器修改了我
9-1-5 类方法参数修饰器
function ParamsDec(params:string){
return function(target:any,funName:string,paramsIndex:number,){ // target: 当前类的显示原型对象 funName : 被修饰的方法名 paramsIndex:被修饰参数的索引
}
}
class Person {
age:number = 20
constructor(){
}
say(@ParamsDec('xxxx') color:string){
console.log(color)
}
}
const son = new Person()