什么是TS
TypeScript 是
JavaScript
的一个超集,主要提供了类型系统和对ES6
的支持,具有可选的类型并可以编译为JavaScript
。从技术上讲TypeScript就是具有静态类型的 JavaScript 。TypeScript
编写的文件以.ts
为后缀,用 TypeScript 编写React
时,以.tsx
为后缀。
安装typescript
命令:npm/cnpm install -g typescript
检查是否安装成功:tsc -v
新建文件
(1)文件目录:创建index.ts
(2)里面写点内容,然后编译tsc index.ts
可能遇到的问题
启动成功后,文件会多出编译后的
index.js
文件,如果在第一次启动tsc index.ts(文件名)
后发现报错,如下图,
- 此时重新以管理员的身份重新打开编辑器,打开终端,然后输入命令:
get-ExecutionPolicy (显示restricted:表示是受限制的);
set-ExecutionPolicy RemoteSigned;(设置)
get-ExecutionPolicy(再次输入,会显示RemoteSigned)
(3)配置文件
//文件tsconfig.json里配置=====根据需求配置
{
"compilerOptions": {
// none、'commonjs','amd','system','es6','es2015','esnext'
"module": "es2015",//指定模块化标准,如果要合并多个模块化的代码就要使用"system"
"target": "es2015",//用来编译什么语法,
"strict": true,
// "lib":[]//指定项目中要使用的库
"sourceMap": true,
"outDir":"./dist",//编译后文件在的目录
"outFile":"./dist/app.js",//将代码合成为一个文件
"allowJs":true,//是否编译js
"checkJs":true,//是否检查js
"removeComments": false,//是否在编译后带有注释
"noEmit": true,//不生成编译文件。
"noEmitOnError":true,//当有错误时,不生成编译文件
"alwaysStrict": true,//用来设置编译后的文件使用严格模式
"noImplicitAny":true,//不允许隐式的any类型
"noImplicitThis": true,//不允许不明确的的this
"strictNullChecks": true,//严格的检查空值;
},
"exclude": ["node_modules"],//不包含
"include": ["./src/**/*"],//src目录下都可以编译
}
typescript语法
- 类型声明:
语法:
let 变量:类型;
let 变量:类型=值;
表示声明一个变量
str
,同时指定它的类型为string
,也就是说只能赋值字符串
的值,其它会报错,如下声明的变量
var str: string = "你好";
var num: number = 2;
2.可以使用|
来表示多个类型
let yan: boolean | string;
yan= true;
yan = "hello"
3.any表示的是任意类型,使用ts
时,不建议用any
类型,相当于没有类型
let d: any;
d = 10;
d = "dddd";
d = true;
- unknown表示未知类型
let e: unknown;
e = true;
e = 'hello';
let s: string;
//s=e 这样不能直接赋值,因为定义的e是未知类型,如果是any就可以
//可判断
if (typeof e === 'string') {
s = e
}
语法:
变量 as 类型 ==> s = e as string
<类型>变量 ==> s = <string> e
- void用来表示空,没有返回值
function fn():void{
}
- object对象
语法:{属性名:属性值,属性名:属性值}
(1)、在属性的后面加上?
,表示属性是可选的,赋值时可写age
也可不写
let d:{str:string,age?:number};
d={str:"董"};
(2)、[proname:string]:any
表示任意类型的属性;
//声明时没有定义age、gender属性,加了[proname:string]:any赋值时是可以的
let c:{str:string,[proname:string]:any};
c={str:"dong",age:12,gender:"男"};
- 设置函数结构类型声明:
语法:
functon fn(参数:类型,参数:类型):类型(返回值的类型){
}
(形参:类型 ,形参:类型 ,....)=>返回值;
function getRest(a: number, b: number): number {
return a + b
}
getRest(2, 5);
let m:(a:number,b:number)=>number;
- 数组Array
(1) 、表示字符串数组
let f:string[];
f=["a","d"]
(2)、表示数字数组
let g:Array<number>
g=[1,2,3]
(3)元组,就是固定长度的数组
let v:[string,number];
v=["22",234]
- &表示同时
let j:{str:string}&{age:number};
j={str:'dong',age:12}
- 类型别名
type mytype=1|2|3|4|5|6;
let k:mytype;
let n:mytype;
k=4;
n=2;
类型推论
如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。
//比如下面的代码,没有写类型,但是它的值是一个字符串,所以再次赋值为数字7是会报错的
let myFavoriteNumber = 'seven';
myFavoriteNumber = 7;//报错
类-------接口
类:定义了一件事物的抽象特点,包含它的属性和方法
1、创建一个类,运用了static静态
class Person{
name:string="孙悟空";
num:number=18;
static age:number=20;//静态属性
// 加上static只能用类Person去调用
static sayhello(){
console.log("age")
}
sayHi(){
console.log(this.num)
}
}
const per=new Person;
Person.sayhello();
per.sayHi()//实例调用
2、抽象方法使用抽象类abstract和继承extends
class Animal {
namestr: string;
age: number;
// 构造函数会在对象创建时调用
//抽象方法使用abstract开头,子类必须对抽象方法进行重写
abstract constructor(namestr: string, age: number) {
this.namestr = namestr;
this.age = age;
}
abstract say(): void;
}
//这里运用了继承========extends ============
class Dong extends Animal {
//当子类用了constructor时,需要用super去复用父类的
constructor(newname: string, age: number) {
super(newname, age);
}
say() {
console.log("汪汪")
}
}
const minzi = new Dong('wang', 6);
console.log(minzi);
minzi.say();
3、修饰属性public、pricate、protected
public
修饰的属性可以在任意位置访问,默认值
private
私有属性 ,私有属性只能在类的内部进行访问
protected
受包含的属性,只能在当前和当前类使用
class Animal {
private namestr: string;//私有属性
protected age: number;
public gender:number;
constructor(namestr: string, age: number,gender:number) {
this.namestr = namestr;
this.age = age;
this.gender=gender;
}
getName(){
return this.namestr;
}
setname(value:string){
this.namestr=value;
}
say(){
console.log(this.age)//6
}
}
const per = new Animal('wang', 6,5);
per.setname("dong")
per.say();
console.log(per.getName())//==>dong
console.log(per.gender)//5
console.log(per.namestr)//报错
4、接口
接口是一种规范的定义,它定义了行为和动作的规范, 定义好接口,用来定义类中包含哪些属性和方法,可以重复申明,接口中的属性不能有实际的值
接口合并
interface myInterface{
name:string,
age:number,
}
interface myInterface{
gender:string,
}
const obj:myInterface={
name:"ddd",
age:2,
gender:'男'
}
函数类型接口
interface encrypt{
(key:string,value:string):string;
}
var md5:encrypt=function(key:string,value:string):string{
return key+value;
}
md5('dong','zhang')
类与接口类型
interface Anmimal{
name:string;
eat(str:string):void;
}
class Dog implements Anmimal{
name:string;
constructor(name:string){
this.name=name;
}
eat(food:string){
console.log(this.name+'吃'+food)
}
}
var dng=new Dog('柯基')
dng.eat('肉')
接口继承
// 接口继承
interface Persen{
eat():void;
}
// PersonOne继承Persen的接口===
interface PersonOne extends Persen{
work():void;
}
// web实现PersonOne的类,所以需要包含它们的方法==
class web implements PersonOne{
public name:string;
constructor(name:string){
this.name=name;
}
eat(){
console.log(this.name+'吃肉---');
}
work(){
console.log(this.name+'做作业')
}
}
let p=new web('小红')
p.eat();//小红吃肉---
p.work();//小红做作业
5、泛型
可以支持不指定数据类型,传入的参数和返回的数据一直,在定义函数或者是类时,如果遇到类型不明确就可以使用泛型
function fn<K>(a: K): K {
return a
}
let result=fn(10)//不指定泛型,TS可以自动对类型进行推测
let result1=fn<string>('dong')//指定类型string
console.log(result,result1)//=>10,dong
function fn2<K,T>(a: K,b:T): K {
console.log(b);//=>bu,dong
return a
}
let result3=fn2(10,"bu")
let result4=fn2<number,string>(23,'dong')
类的泛型
class MinClass<T>{
public list: T[] = [];
add(value: T): void {
this.list.push(value)
}
min(): T {
var minNum = this.list[0];
for (var i = 0; i < this.list.length; i++) {
if (minNum > this.list[i]) {
minNum = this.list[i]
}
}
console.log(minNum)//88
return minNum;
}
}
var mi=new MinClass<number>();//这里定义的参数是number
mi.add(99);
mi.add(88);
mi.min()
6、命名空间
内部模块,主要用于组织代码,避免命名冲突,一个模块里可能会有多个命名空间,各个命名空间里的相同类名或者接口不冲突
// 用了命名空间相当于私有空间,
namespace A {
interface Anmimal {
name: string;
eat(str: string): void;
}
//里面的方法或者类需要`export`暴露出去
export class Dog implements Anmimal {
name: string;
constructor(name: string) {
this.name = name;
}
eat(food: string) {
console.log(this.name + '吃' + food)
}
}
}
// 实例化时用命名的A去获取
var d = new A.Dog('zhangsan');
d.eat('肉')
7、装饰器
装饰器
:是一种类型的声明,它能够被附加到类声明,方法、属性或参数上,可以修改类的行为。通俗讲:就是一个方法
,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。分两类:普通装饰器(无法传参)、装饰器工厂(可传参)
- 普通装饰器(无法传参)
function logClass(params:any){
console.log(params)//@logClass如果没有传参数params就是当前的类HttpClient
// 扩展属性和方法==
params.prototype.apiUrl='动态扩展的属性';
params.prototype.run=function(){
console.log("跑步=====")
}
}
@logClass
class HttpClient{
constructor(){}
getDate(){}
}
var http:any =new HttpClient();
console.log(http.apiUrl);//动态扩展的属性
http.run();//跑步=====
- 装饰器工厂(可传参)
function logClass(params: string) {
console.log(params)
//params传过来的参数====(我是来学ts的)
return function (target: any) {
// target就是类HttpClient
target.prototype.apiUrl = params;
}
}
@logClass('我是来学ts的')//传的参数
class HttpClient {
constructor() {}
getDate() {}
}
var http: any = new HttpClient();
console.log(http.apiUrl);//动态扩展的属性
- 修改方法及属性装饰器
//类装饰器修改属性及方法数据
function logClass(target: any) {
//target=>类HttpClient
return class extends target {
str: any = '我是修改后的属性';
getDate() {
console.log(this.str)//我是修改后的属性
}
}
}
// 属性装饰器=====
function logParams(params: any) {
console.log(params)//传的参数(我是属性装饰器---)
return function (target: any, attr: any) {
console.log(target);//=>类
console.log(attr);//属性=>str
target[attr] = params;//加上这个会显示str'我是属性装饰器---'
}
}
@logClass
class HttpClient {
@logParams('我是属性装饰器---')
public str: string | undefined;
constructor() {
this.str = '我是构造函数里的str'
}
getDate() {
console.log(this.str)
}
}
var http = new HttpClient();
http.getDate()
console.log(http.str);//=>我是修改后的属性
- 方法装饰器及修改方法传参的类型
function getMethods(params: any) {
return function (target: any, methods: any, desc: any) {
console.log(target);
console.log(methods);//方法的名字
console.log(desc.value);//=>getDate()方法===
// 扩展属性和方法=====
target.str = '修改后的===';
target.run = function () {
console.log('run')
}
// 修改装饰器的方法,把装饰器方法里面传入的所有参数改为string类型
//保存当前的方法
var oMethods = desc.value;
// 改变参数的类型===
desc.value = function (...args: any[]) {
args = args.map((value) => {
return String(value);
})
console.log(args)
oMethods.apply(this,args)
}
}
}
class HttpClient {
public str: string | undefined;
constructor() {
// this.str = '我是构造函数里的str'
}
@getMethods('http://www.baidu.com')
getDate(...args: any[]) {
console.log(args);
}
}
var http: any = new HttpClient();
http.run();
console.log(http.str);
http.getDate(123, 123)
有了ts,好像就不用写typeof了,也不用检查拿到的数据是不是string、number、undefined、null了,给程序带来了稳定性和可预测性,方便debug。😊😊😊😊😊😊