ts的优点:静态编译提示错误,强类型,接口和继承,是js的超集,需要编译后执行
编译
1、ts后缀建立文件后通过tsc进行指定文件的编译,不带任何输入文件的情况下调用tsc,编译器会从当前目录开始去查找tsconfig.json文件,逐级向上搜索父目录。
2、不带任何输入文件的情况下调用tsc,且使用命令行参数--project(或-p)指定一个包含tsconfig.json文件的目录。
3、当命令行上指定了输入文件时,tsconfig.json文件会被忽略。
4、直接通过ts test.ts会生成对应的js文件
5、通过sudo npm install ts-node -g --save --unsafe-perm=true --allow-root安装依赖 可通过ts-node test.ts直接执行
6、通过配置vscode实现执行tsc --init 生成文件 tsconfig.json,修改路径和添加watch监听实现自动监控ts文件生成js: https://www.cnblogs.com/liangyy/p/12436720.html
tsconfig.json配置文件
配置示例
{
"extends": "./configs/base",
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"types" : ["node", "lodash", "express"],
"typeRoots" : ["./typings"]
},
"files": [
"core.ts",
"sys.ts",
"types.ts"
],
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
- extends 拓展配置文件 引入的会覆盖当前的源文件配置
- 默认配置下会编译当前目录以及子目录下的所有文件 排除可能是输出文件 支持拓展名为ts tsx d.ts 当allowJs设置为true则包含js jsx拓展名
- 当配置了files之后只会引入对应的配置下的文件,优先于exclude指定的排除文件
- include和exclude指定匹配模式,支持(匹配0+多个字符不包含目录)? (匹配一个任意字符)*/ (递归匹配任意子目录)
- 默认所有可见的@types包都会在编译时包含进来,node_modules/@types文件夹下以及子文件下所有包都是可见的,当被置顶了typeRoots则只有被指定的包会被包含进来,指定了types则node_modules/@types下的这些包会被引入进来,可以通过指定types:[]来禁用自动引入
基础语法
1、number boolean string null undefined指定五种基本类型,void指定空值可以赋值为null undefined,反之void不可赋值给任何类型;any代表任意类型的值(类似不写);类型推论,当你定义变量的时候赋值,ts会根据你的赋值推出一个类型,不进行赋值则会默认为任意值;联合类型:通过|分隔多个类型,访问属性/方法时只能是共有的,当赋值后则会类型推断
2、接口:通过interface关键字进行定义,?可选属性、[propName: type] 自定义属性(自定义属性后,其他属性必须为自定义属性的子类)、readonly只读属性
- 接口描述了ts种复杂的类型结构,接口继承自类的时候继承了它的成员但是没有继承实现,所以接口的功能只能由子类来实现。
3、数组类型number[]或者Array<number>;也可以通过接口定义(复杂),其他类数组类型有自己的类型定义如IArguments NodeList
4、函数有两种定义方式,通过?进行可选参数定义,只能写在最后,如果是写了默认值的参数,ts认为是可选参数,且无位置要求,通过解构获取剩余参数,也可进行定义
5、断言 as语法:只要A兼容B或者B兼容A,就可以互相断言,子类可以被断言为一个父类,父类断言可以为子类,是因为子类包含父类的所有属性,可以访问到父类的内容
6、声明文件一种是放在源码里,通过types指定文件目录;一种是补充到type库,最后是自己实现.d.ts文件
7、type指定类型别名,类型约束
8、元组,赋值时需要匹配,可单独赋值,可越界为联合类型
9、enum 枚举类型可以手动覆盖;可以包含计算值,下一个加一; 常数枚举类型不可计算,外部枚举类型 declare
10、类:public private protected abstract,抽象类必须被子类实现
11、接口继承类:ts中的类在声明时同时创建了一个同名的类型,它包含了属性和方法,没有constructor和static属性,接口继承时继承了这部分类型,类似继承了类生成的实例
类 接口 函数的用法
1、类 跟es6中的类差不多,添加了修饰符:public protected private,以及readonly;如果是抽象类abstract则不能直接实例化,抽象类中的抽象属性和方法必须被子类实现,类和接口很像,他们的区别在于:
- 类通过class实现,通过extends继承被子类继承;接口是通过interface定义,被类所实现
- 类的方法可以自己实现,抽象类子类必须实现;接口则是一组规则的定义
- 类通常是对一个类别的公共部分做抽象,有规律;接口只是抽象,可能并无关联
2、接口:接口中可以定义可选属性,索引属性,只读属性;也支持定义函数以及构造函数的类型
- 函数重载 根据不同的参数个数指定不同的类型
- this指向 由于运行时才能确定this指向,在ts中可以进行手动的this指向
3、泛型 通过T来代指当运行时才能确认的类型,难点在于结合keyof和T<k>使用
4、兼容 如A=B,协变是B包含A,逆变是A包含B,双向协变是没有规则
对象、函数返回值、类中采用的是协变
函数参数个数的兼容采用的是逆变
函数参数的兼容和泛型用的是双向协变
- 函数参数和返回值的类型:https://jkchao.github.io/typescript-book-chinese/tips/covarianceAndContravariance.html#%E4%B8%80%E4%B8%AA%E6%9C%89%E8%B6%A3%E7%9A%84%E9%97%AE%E9%A2%98
总结:(Animal → Greyhound) 可以正确传入 (Dog → Dog) , 说明返回值是协变的,参数是逆变的。
function greeter(person:string) {
return "Hello, " + person;
}
let user = ["Jane User"];
// document.body.innerHTML = greeter();
let u: void
// let num: number = u
let anyThind: any = 'hello'
console.log(anyThind.myName)
let from: string|number
from.toString()
from.length
from = 'z'
from.length
interface Person {
name: string
age: number
}
let child:Person = {
name: 'zz',
age: 12
}
interface Person {
readonly id:number
name: string
age?:number
[propName: string]: string|number
}
let child1: Person = {
id:1,
name: 'z',
class: 1
}
child1.id = 2
// 数组
let list: number[] = [1]
let list2: Array<number> = [2]
interface IList {
[index:number]: number,
length:number,
callee: Function
}
function sum() {
let args: IList = arguments
}
// 函数
function myName(x:number,y:number, ...items: any[]): number {
return x+y
}
let mySum: (x:number, y:number) => number = function(x:number, y:number):number {return x+y}
// 函数重载
function reverse(x:number): number
function reverse(x:string): string
function reverse(x: string|number): number| string {
return x
}
// 断言和声明
interface Animal {
name: string
}
interface Cat {
name: string,
voice: string
}
let animal:Animal = {
name: 'tom'
}
// 断言只需要有互相包含的关系
let bai = animal as Cat
// 赋值必须满足前者兼容后者
let baige2:Cat = {
name: 'baige',
voice: 'miao'
}
let baige:Cat = animal //失败
// 类型别名
type stringName = string
let names: stringName = 'owo'
// 类型约束
type EventNames = 'click' | 'scroll' | 'mousemove'
// 元组
let tom: [string, number]
tom[0]='first'
tom = ['second',0]
tom.push(3)
// 枚举
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat}
// 类
abstract class Animals {
public name;
public constructor(name) {
this.name = name
}
public abstract voice()
}
class Cats extends Animals {
public voice() {
// 必须要实现抽象类的属性
}
}
let miao = new Cats('bai')
// 泛型 后置确定类型 可定义约束
function copyFields<T extends U, U>(target: T, source: U): T {
for(let id in source) {
target[id] = (<T>source)[id]
}
return target
}
let x = {a:1, b:2}
let y = {b:10}
copyFields(x, y)