1.ts介绍
微软开发的开源编程语言,是js的超集。
2.安装
yarn global add typescript
3.运行
编译ts文件
tsc index.ts
初始化配置文件
tsc --init
会生成tsconfig.json文件
4.ts中的数据类型
布尔类型(boolean)
数字类型 (number)
字符串类型 (string)
数组类型 (array)
元组类型 (tuple)
枚举类型(enum)
任意类型(any)
unknown
null和undefined
void类型
never类型
- 布尔类型,数字类型,字符串类型
let bol:boolean=true; //只能是true或者false
let bol1:boolean=undefined; // error
let str:string=""; // 只能是字符串
let str1:string="aa"; // 只能是字符串
let num: number=1;//整数可以
let num1:number=1.12; //浮点数可以
let num2:number=NaN;//NaN可以
- 数组类型
let arr:number[]=[1,2,3,4]// 纯数字数组
let arr2:string[]=['1','2']// 纯字符串数组
let arr3:string[]=[]// 允许是空数组
arr3.push("123")// ok
arr3.push(123)// error 数组只能包含字符串
let arr4:any[]=[1,false,'haha'];//任意类型填充的数组用any
数组的另一种表示方法
let arr5:Array<string>=['hahah'];
let arr6:Array<number>=[1,2,3];
。。。
- 元组类型tuple(数组的一种)
个数、类型必须严格遵守
let arr:[string,number]=['haha',12];
let arr1:[string,number]=['haha'];//error
let arr2:[string,number]=['haha',12,1];//error
- 枚举类型(enum)
提升代码的可读性,可用于将状态码映射成数字
enum Flag {
success=1,
error=-1
}
let f:Flag=Flag.success; //1
Flag.success //1
Flag.error // -1
没有赋值的情况
enum Color {
red,
blue,
orange=10,
black,
}
//如果没有赋值就取自己的索引,如果有值就取值,后边的是前边的值+1
Color.red // 0
Color.blue // 1
Color.orange // 10
Color.black // 11
- 任意类型 any
let n:any=123;//可以赋任何值
n='haha';
n=false;
n.foo.bar; // OK 不进行验证
n.trim(); // OK 不进行验证
let arr:any[]=[1,false,'haha']//可以是任何类型
- unknown类型
// unkonwn 类型只能被赋值给any和unknown本身 只有能保存任意类型值的容器才能保存unknown本身
let u: unknown = 123;
u='aaa';
let a: string = u; // not ok;
- null和undefined
let un:undefined;
console.log(un)//输出undefined
//“或者”用“ | ”表示
let un2:number | undefined | string | null;
un2=11;
console.log(un2);//11
let un3:null;
console.log(un3)//error 因为是undefined
let un4:null;
un4=null
console.log(un4)//null
let un5:null=null;
console.log(un5)//null
- void类型:ts中的void表示没有任何类型,一般用于定义的方法没有返回值
function fn():void{
console.log(1)
}
fn()//1
function fn2():void{
console.log(1)
return 1
}
//error
- never类型
var a:never;
a=(()=>{
throw new Error('错误');
})()
5.函数的写法
//设置返回值必须是字符串
function run():string{
return 'haha';
}
let run2=function():string{
return 'haha';
}
//设置函数参数的类型
let run3=function(name:string,age:number):string{
return `${name}---${age}`;
}
run3('ts',20)// 'ts---20'
//没有返回值的函数
let run4=function(name:string,age:number):void{
console.log( `${name}---${age}`)
}
run4('ts',20)// 'ts---20'
//可选参数 " ? " 表示,可选参数必须配置到参数的最后面
let run5=function(name:string,age?:number):string{
if(age){
return `${name}---${age}`
}else{
return `${name}---空`
}
run5('ts',20)// 'ts---20'
run5('ts')// 'ts---空'
//默认参数
let run6=function(name:string,age:number=10):void{
console.log( `${name}---${age}`)
}
run6('ts',20)// 'ts---20'
run6('ts')// 'ts---10'
//剩余参数
function sum(a:number,b:number,c:number):number{
return a+b+c
}
sum(1,2,3)//6
function sum2(...res:number[]):number{
return res.reduce((prev,next)=>{
return prev+next
},0)
}
sum2(1,2,3)//6
function sum4(a:number,...res:number[]):number{
return res.reduce((prev,next)=>{
return prev+next
},a)
}
sum4(1,2,3)//6
//ts函数的重载(重载指的是两个或者以上的同名函数,但他们参数不一样,这是会出现重载的情况)
function getInfo(name:string):string
function getInfo(age:number):string
function getInfo(str:any):any{
if(typeof str==='string'){
return `name-${str}`
}else{
return `age-${str}`
}
}
getInfo('zhang')// name-zhang
getInfo(12)// age-12
//箭头函数 和以上规则一致
var fun3 = (a:number, b:number):number=>{
return a+b;
}
- ts中的类class
class Person{
name:string;
constructor(n:string){
this.name=n;
}
run():void{
alert(this.name);
}
work():string{
return this.name;
}
}
var p=new Person('张三');
p.run();//张三
//类的继承
class Workers extends Person{
constructor(name:string){
super(name);
}
}
let work = new Workers('里斯');//里斯
work.run()
//类里边的修饰符 ts里边定义属性的时候提供了三个修饰符
//public公有的 :< 在类里边、子类、类外边都可以访问 >
//protected受保护的 : < 在类里边、子类里边可以访问、在类外部没法访问 >
//private私有的 : < 在类里可以访问,子类、类外部都没法访问 >
//属性如果不加修饰符默认是 public 公有的
class Person{
public name:string;//------可不写public-------
constructor(n:string){
this.name=n;
}
run():string{
return this.name//类里边访问
}
}
var p=new Person('张三');
p.name;//类外边访问
class Workers extends Person{
constructor(name:string){
super(name);
}
work():void{
alert(this.name)//子类里边访问
}
}
//-----------protected受保护的-------------
class Person{
protected name:string;
constructor(n:string){
this.name=n;
}
run():string{
return this.name//类里边访问
}
}
var p=new Person('张三');
p.name;//-----------类外边访问 error---------
class Workers extends Person{
constructor(name:string){
super(name);
}
work():void{
alert(this.name)//子类里边访问
}
}
//---------------private--------------------
class Person{
private name:string;
constructor(n:string){
this.name=n;
}
run():string{
return this.name//类里边访问
}
}
var p=new Person('张三');
p.name;//-----------类外边访问 error-----------
class Workers extends Person{
constructor(name:string){
super(name);
}
work():void{
alert(this.name)//------子类里边访问 error-----------
}
}
//ts中的抽象类,他是提供继承的基类,不能被直接实例化
//用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
//abstract的抽象方法只能放到抽象类中
abstract class Animal{
public name:string;
constructor(name:string){
this.name=name;
}
abstract eat():any;
run(){
console.log('其他方法可以不实现')
}
}
let a=new Animal()//错误的写法
class Dog extends Animal{
constructor(name:string){
super(name);
}
//**抽象类的子类必须实现抽象类里边的抽象方法**
eat(){
console.log(this.name)
}
}
let d=new Dog('狗');
d.eat();
6.接口 interface
接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批所需要遵守的规范,接口不关心这些类内部状态数据,也不关心类方法里的实现细节,他只规定这批类必须提供的某些方法,提供这些方法的类就可以满足实际需要。
-
接口类型:
属性类接口、函数类型接口、可索引接口、类类型接口、接口拓展1.属性类接口 对json的约束
function fn1(obj:{name:string}):void{ console.log(obj.name) } fn1({name:'hello'})// hello fn1({name:123})// error fn1({name:'hello',age:2})// error //interface写法 对批量方法传入参数都进行约束 interface FullName{ firstName:string; //注意‘ ; ’结束 lastName:string; }; function fn2(obj:FullName):string{ return obj.firstName+obj.lastName; } fn2({firstName:'hello',lastName:'ts'});//必须只包括着两个属性 fn2({firstName:'hello',lastName:'ts',age:12});// error let obj={ firstName:'hello', lastName:'ts', age:12 } fn2(obj);//这样传入的obj只要包含两个属性即可,但是函数内不允许使用age属性 //可选属性接口 interface FullName{ firstName:string; //注意‘ ; ’结束 lastName?:string; }; //可以这么用 fn2({firstName:'aaa'}); fn2({firstName:'aaa',lastName:'bbb'});
2.函数类型接口:对方法传入的参数 以及返回值进行约束
interface encrypt{ (key:string,value:string):string } let md5:encrypt=function(key:string,value:string):string{ return key+value; } // 或这样写 let md6:encrypt=function(key,value){ return key+value; }
- 可索引接口: 对数组、对象的约束(不常用)
// let arr:number[]=[1,2,3];//数组类型 // 对数组的约束 interface UserArr{ [index:number]:string// index属性是number类型,值是string类型 } let arr:UserArr=['1','2'] // 对对象的约束 interface UserArr{ [index:string]:string// index属性是string类型,值是string类型 } let obj:UserArr={name:'aaa'}
- 类类型接口(implements) 和抽象类相似
interface Animal{ name:string; eat(str:string):void; } // Dog必须包含name和eat class Dog implements Animal{ name:string; constructor(name:string){ this.name=name; } eat(str:string):void{ console.log(this.name+str) }; run(str:string):void{ console.log('run'); } } let d=new Dog('小黑'); d.eat('古,头')
- 接口扩展,接口可以继承接口
interface Animal1{ eat():void; } interface Person1 extends Animal1{ work():void; } class Web1 implements Person1{ constructor(){/**do some**/} eat(){/**do some**/}; work(){/**do some**/} } let w=new Web1(); class Pro{ public name:string; constructor(name:string){ this.name=name; } coding(code:string):void{ console.log(this.name+code) } //add eat ,Web2就可以不用再定义eat eat(){}; } class Web2 extends Pro implements Person1{ constructor(name:string){ super(name) } // eat(){}; work(){} } let w2=new Web2('123');
type类型别名
- 类型别名会给一个类型起个新名字。 类型别名有时和接口interface很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。
- 可以使用 &交叉类型 和 |联合类型。
- 不能使用extends和implements
interface定义一个实实在在的接口,是一个真正的类型 / type一般指一个别名,不会产生真实的类型。
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
type Container<T> = { value: T };
7.泛型<T>
为了组件的灵活性,组件不仅能够支持当前的数据类型,同时也应该能支持未来的数据类型,,一个组件可以支持多种数据类型。这样用户就可以以自己的数据类型来使用组件。
泛型就是解决 类、接口、方法的复用性、以及对不特定的数据类型的支持(类型校验)
- 泛型函数
// any可以解决问题,它放弃了类型检查
// 泛型:可以支持不特定的数据类型,要求传入的参数和返回的参数一致
function getData<T>(value:T):T{// T表示泛型,具体什么类型是调用这个方法的时候决定的
return value
}
getData<number>(123);//参数必须是number
getData<string>('123');//参数必须是string
getData<number>('aaa'); // error
- 泛型类
class MinClass<T>{
public list:T[]=[];
add(value:T):void{
this.list.push(value);
}
min():T{
let min=this.list[0];
for(let i=0;i<this.list.length;i++){
if(min>this.list[i]){min=this.list[i]}
}
return min;
}
}
let m1=new MinClass<number>()//传入的参数只能是number
//实例化类,并且制定了类的T代表的类型是number
m1.add(2);
m1.add(1);
m1.add(3);
m1.min();
react中使用泛型
type Props = {
className?: string
...
};
type State = {
submitted?: bool
...
};
class MyComponent extends React.Component<Props, State> {
...
}
- 泛型接口
interface ConfigFn{
<T>(value:T):T
}
let getDate:ConfigFn=function<T>(value:T):T{
return value;
}
getDate<string>('值value')
//另一种写法
interface ConfigFn<T>{
(value:T):T
}
function getData3<T>(value:T):T{
return value;
}
var myGetData:ConfigFn<string> = getData3;
myGetData('值value')
myGetData(20)// REEOR
- 泛类
泛型可以帮助我们避免重复的代码以及对不特定数据类型的支持
- 定义个类;
- 把类作为参数来约束数据传入的类型
//操作数据库的泛型类
class MysqlDb<T>{
add(info:T):boolean{
console.log(info);
return true;
}
}
//1.定义一个user类,和数据库进行映射
class User{
username:string|undefined;
pasword:string|undefined;
}
let u=new User();
u.username='haha';
u.pasword="1234";
let Db=new MysqlDb();
Db.add(u);
symbols 和es6的一致 一种新的数据额类型
let sym2 = Symbol("key");
let sym3 = Symbol("key");
sym2 === sym3; // false, symbols是唯一的
//像字符串一样,symbols也可以被用做对象属性的键。
let sym = Symbol();
let obj = {
[sym]: "value"
};
console.log(obj[sym]); // "value"
// Symbols也可以与计算出的属性名声明相结合来声明对象的属性和类成员
const getClassNameSymbol = Symbol();
class C {
[getClassNameSymbol](){
return "C";
}
}
let c = new C();
let className = c[getClassNameSymbol](); // "C"
命名空间 namespace
// 相当于一个自执行函数
//定义一个namespace 暴露里边的变量、函数等数据需要使用export导出,不导出的外部无法使用
namespace Validation {
export interface StringValidator {//暴露类类型接口
isAcceptable(s: string): boolean;
}
const lettersRegexp = /^[A-Za-z]+$/;
const numberRegexp = /^[0-9]+$/;
export class LettersOnlyValidator implements StringValidator {//暴露一个类
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
export class ZipCodeValidator implements StringValidator {//暴露一个类
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
}
new Validation.LettersOnlyValidator().isAcceptable("123");
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
声明合并
//1.合并接口
// 同名接口会合并、
// 同属性接口必须类型一致、
// 接口定义会被提升,合并也会被提前编译、
// 使用合并后的接口必须包含所有的属性、
interface Box {
height: number;
width: number;
}
let box1: Box = {height: 5, width: 6};//报错 跟代码顺序无关
interface Box {
height: number;
width: string;//同名属性,类型不一样,合并会报错
scale: number;
}
let box: Box = {height: 5, width: 6, scale: 10};
let box2: Box = {height: 5, width: 6};//报错 必须包含合并后接口的所有属性
对于函数类型接口,每个同名函数声明都会被当成这个函数的一个重载。 同时需要注意,当接口 A与后来的接口 A合并时,后面的接口具有更高的优先级。
装饰器decorators
能够被附加到类声明、方法、属性、参数上
//装饰器
function sealed(target) {
// target就是被装饰的函数、类或者其他
}
@sealed
XXX类{
xxx
}
//等价于sealed(XXX类)
//装饰器工厂
function color(value: string) { // 这是一个装饰器工厂
return function (target) { // 这是装饰器
// do something with "target" and "value"...
}
}
@color('res')
XXX类{
xxx
}
//等价于color('red')(XXX类)
//分类
//1.类装饰器
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
function sealed(constructor: Function) {
console.log(constructor)//Greeter
}
//2.方法装饰器
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@sealed
greet() {
return "Hello, " + this.greeting;
}
}
function sealed(target,fnName,desc) {
console.log(target)//函数本身
console.log(fnName)//函数名
console.log(desc)//函数描述
}
//3.属性装饰器
class Greeter {
@sealed
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
function sealed(target,attr) {
console.log(target)//实例对象
console.log(attr)//属性名
}
//4.参数装饰器
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet(@sealed g:string) {
return g + this.greeting;
}
}
function sealed(target,fnName,index) {
console.log(target)//实例对象
console.log(fnName)//函数名
console.log(index)//当前参数的索引
}