02|typescript常用实例
一、定义索引数组
interface StringArray{
[index: number]: string
}
let chars: StringArray = ['A', 'B']
interface Names{
[x:string]: string,
[y:number]: string
}
二、定义函数
//example one
function add(x:number, y:number){
return x + y
}
//example two
let add:(x:number, y:number) => number
//example three
interface add{
(x:number, y:number): number
}
//example four
type Add = (x:number, y:number) => number
//实现具体的函数
let add:Add = (a,b) => a + b
// 定义混合类型
interface Lib{
(): void; //表明Lib类是一个不带返回值得函数
version: string; //表明Lib类有version这个属性
dosomething():void // 表明Lib类有dosomething这个方法
}
function getLib(){
let lib:Lib = (() => {}) as Lib;
lib.version = '1.0.1';
lib.dosomething = () => {}
return lib;
}
let lib1 = getLib()
lib1()
lib1.dosomething()
函数参数可选
function add5(x:number,y?:number){
return y ? x + y : x;
}
函数参数默认值
function add6(x:number, y=0, z:number,q=1){
return x + y + z + q
}
console.log(add6(1, undefined, 3))
函数参数的剩余变量
function add7(x:number, ...rest:number[]){
return x + rest.reduce((pre, cur) => pre + cur)
}
console.log(add7(1,2,3,4,5))
函数的重载
// 函数的重载
function add8(...rest:number[]):number;
function add8(...rest:string[]):string;
function add8(...rest:any[]):any{
let first = rest[0];
if(typeof first === 'string'){
return rest.join('')
}
if(typeof first === 'number'){
return rest.reduce((pre, cur) => pre + cur)
}
}
console.log(add8(1,2,3))
console.log(add8('a','b','c'))
三、ts中的类
类的定义
class Dog {
constructor(name:string){
this.name = name
}
name: string
run(){}
}
console.log(Dog.prototype) //{run: ƒ, constructor: ƒ}
let dog =new Dog('wangwang')
console.log(dog) // Dog {name: "wangwang"}
类的继承
class Husky extends Dog{
constructor(name:string, color:string){
super(name);
this.color = color;
}
color:string
}
类的修饰符
1、public 默认设置
2、protected: 只能在类自身和子类中使用(也就是只能继承)
3、private:只能在类本身使用
4、readonly: 只读属性
5、static:静态修饰符(只能通过类名来调用,也可以被继承)
6、构造函数的参数用修饰符修饰后,会转化成示例属性
class Husky extends Dog{
constructor(name:string, public color:string){
super(name);
this.color = color
}
// color:string
}
let husky = new Husky('wangwang','white')
console.log(husky)
抽象类
抽象类只能被继承,不能被实例化
抽象方法的好处是,明确知道子类中有具体的实现,所以就不在父类中实现了
抽象类的好处就是能抽出事务共性,有利于代码的复用和扩展
abstract class Animal{
eat(){
console.log('eat')
}
abstract sleep():void
}
//let animal = new Animal() //Cannot create an instance of an abstract class.ts(2511)
class Dog extends Animal{
constructor(){
super();
}
sleep(){
console.log('sleep...')
}
}
let dog = new Dog()
dog.eat()
抽象类实现多态
abstract class Animal{
eat(){
console.log('eat')
}
abstract sleep():void
}
//let animal = new Animal() //Cannot create an instance of an abstract class.ts(2511)
class Dog extends Animal{
constructor(){
super();
}
sleep(){
console.log('Dog sleep...')
}
}
class Cat extends Animal{
sleep(){
console.log('Cat sleep...')
}
}
let dog = new Dog()
let cat = new Cat()
let animals: Animal[] = [dog, cat]
animals.forEach(i => {
i.sleep()
})
image.png
通过返回this实现链式调用
class WorkFlow{
step1(){
return this;
}
step2(){
return this;
}
}
new WorkFlow().step1().step2()
继承的时候 this也可以表现出多态,既可以是父类型,也可以使子类型
class WorkFlow{
step1(){
return this;
}
step2(){
return this;
}
}
class MyFlow extends WorkFlow{
next(){
return this;
}
}
new MyFlow().next().step1().next().step2()
四、ts中接口与类的关系
一个接口可以约束一个类成员有哪些属性以及他们的类型
类实现接口时,必须要实现接口所有的属性和方法
接口只能约束类的公用成员
接口不能约束类的构造函数
interface Human{
name: string;
eat():void;
}
class Asian implements Human{
constructor(public name: string){
this.name = name
}
eat(){}
sleep(){}
}
接口也可以继承接口
一个接口可以继承多个接口
可以抽离处可重用的接口,也可以将多个接口合并成一个接口
interface Human{
name: string;
eat():void;
}
class Asian implements Human{
constructor(public name: string){
this.name = name
}
eat(){}
sleep(){}
}
interface Man extends Human{
run(): void
}
interface Child{
cry():void
}
interface Boy extends Man,Child{}
let boy:Boy = {
name: '',
run(){},
eat(){},
cry(){}
}
接口可以继承类,接口将类的成员抽象了出来,只有类的成员结构,没有具体的实现
class Auto {
state = 1
}
interface AutoInterface extends Auto{
}
class C implements AutoInterface{
state = 1
}
class Bus extends Auto implements AutoInterface{
}
let c = new C();
console.log(c.state)
image.png
五、ts中的泛型
可以自定义化函数参数的类型
使用泛型定义一个函数
function log<T>(value: T): T{
console.log(value)
return value
}
log<string[]>(['a', 'b'])
log(['a','b'])
使用泛型定义一个函数类
function log<T>(value: T): T{
console.log(value)
return value
}
log<string[]>(['a', 'b'])
log(['a','b'])
type Log = <T>(value: T) => T
let myLog:Log = log
使用泛型定义接口
interface Log{
<T>(value: T): T
}
function log<T>(value: T):T{
console.log(value)
return value
}
interface Log<T = string>{
(value: T): T
}
// let myLog: Log<number> = log
let myLog: Log = log;
泛型不能约束类的静态成员
class Log<T>{
// Static members cannot reference class type parameters.ts(2302)
static run(value: T){
console.log(value)
return value
}
}
interface Length{
length: number
}
function log<T extends Length>(value: T): T{
console.log(value, value.length)
return value
}
log([1])
log('123')
log({length: 1})
泛型的好处
1、函数和类可以轻松地支持多种类型,增强程序的扩展性
2、不必写多条函数重载,很长的联合类型声明,增强代码可读性
3、灵活控制类间的约束
六、类型兼容性
(一)、接口的兼容性
X 兼容 Y: X(目标类型) = Y(源类型)
interface X{
a: any;
b: any;
}
interface Y {
a: any;
b: any;
c: any;
}
let x: X = {a: 1, b: 1}
let y: Y = {a:1, b:2, c:3}
x = y
// y = x // Y 不兼容 X
(二)、函数的兼容性
1)参数的个数
参数少的 兼容参数多的
// 函数的兼容性
type Handler = (a:number) => void;
function hof(handler: Handler){
return handler;
}
// 1)参数的个数
let handler1 = (a:number) => {}
hof(handler1)
let handler2 = (a:number,b:number) => {}
hof(handler2) ////Argument of type '(a: number, b: number) => void' is not assignable to parameter of type 'Handler'.ts(2345)
/**固定参数可以兼容可选参数和剩余参数**/
/**可选参数是不兼容固定参数和剩余参数的**/
/**剩余参数是可以兼容可选参数和固定参数的**/
let a = (p1:number, p2:number) => {}
let b = (p1?:number, p2?:number) => {}
let c = (...args:number[]) => {}
// ok
a = b;
a = c;
// unassignable
b = a;
b = c;
// ok
c = a
c = b
2)参数的类型
类型多的兼容类型少的
interface Point3D{
x: number
y: number
z: number
}
interface Point2D{
x: number
y: number
}
let p3d = (point: Point3D) => {}
let p2d = (point: Point2D) => {}
// ok
p3d = p2d
// assignable
p2d = p3d
3)参数的返回值类型
返回值多的兼容返回值多少的(鸭式变形法)
let p3d = (point: Point3D) => {}
let p2d = (point: Point2D) => {}
let f = () => ({name: 'Alice'})
let g = () => ({name: 'Alice', location:'beijing'})
// ok
f = g
// unassignable
g = f
function overload(a:number, b:number): number;
function overload(a:string, b:string): string;
function overload(a: any, b:any): any {}
(三)、枚举的兼容性
枚举类型和数字是可以相互兼容的
enum Fruit { Apple, Banana }
enum Color { Green, Red }
let fruit: Fruit.Apple = 3
let no:number = Fruit.Apple
枚举类型是不相互兼容的
let color: Color = Fruit.Apple // Type 'Fruit.Apple' is not assignable to type 'Color'.ts(2322)
(四)、类的兼容性
类之间只要有相同的实例属性和方法,就可以兼容,静态/构造属性、方法不参与兼容性比较
class A {
constructor(p:number, q:number){}
id: number = 1
}
class B {
static s = 1;
constructor(p: number){}
id: number = 1
}
let aa = new A(1,2)
let bb = new B(2)
// ok
aa = bb
// ok
bb = aa
当类中存在private私有变量时,只有子类和父类兼容
class A {
constructor(p:number, q:number){}
id: number = 1
private name = 'antiai'
}
class C extends A{}
let aa = new A(1,2)
let cc = new C(1,2)
aa = cc
cc = aa
(四)、泛型的兼容性
只有类型参数T被泛型接口使用的时候,才会影响泛型的兼容性
// 兼容
interface Empty<T>{
}
let obj1: Empty<number> = {}
let obj2: Empty<string> = {}
obj1 = obj2
obj2 = obj1
// 不兼容
interface Empty<T>{
value: T
}
let obj1: Empty<number> = {}
let obj2: Empty<string> = {}
obj1 = obj2
obj2 = obj1
(五)、泛型函数的兼容性
如果两个泛型参数的定义相同,但是没有指定类型参数,他们之间也是相互兼容的
let log1 = <T>(x: T) => {
console.log(x)
return x
}
let log2 = <U>(y: U) => {
console.log(y)
return y
}
log1 = log2
log2 = log1
结构之间兼容:成员少的兼容成员多的
函数之间兼容:参数多的兼容参数少的