• 作者:老汪软件技巧
  • 发表时间:2024-09-05 10:02
  • 浏览量:

interface

上集谈到用type来自定义一些类型,事实上也可以通过interface来定义。

// type Person = {
//     firstName:string,
//     lastName:string,
//     age:number
// }
interface Person {
    firstName: string,
    lastName: string,
    age: number
}
let p:Person = {
    firstName : '张',
    lastName:'三',
    age:20
}

interface和type的区别

事实上他们的相似度非常高,但是有一些语法上的差异

type我们又称之为别名,interface接口,语法上来说type可以定义联合类型、交叉类型、对象,而interface用于定义对象

// type 别名
type A = {
  name: string;
  age: number;
};
// type 联合类型
type B = string | number;
// interface
interface C {
  name: string;
  id: number;
}

继承type不能继承,interface可以继承interface也可以继承type。当然,也可以一次继承多个。

type Foo = {
    a:string
}
interface A extends Foo{
    b:number   
}
const obj : A = {
    a:'hello',
    b:123
}
// interface 扩展
interface Animal {
  name: string;
}
interface Bird extends Animal {
  honey: boolean;
}
const bird: Bird = {
  name: "bird",     
  honey: true,
};

class关键字不仅可以用作定义构造函数,他也可以当成值类型来用

// 除此之外,class关键字不仅可以用作定义构造函数,他也可以当成值类型来用
class A {
    x: number = 123
    y(): number {
        return 1
    }
}
interface B extends A {
    z: string
}
const b: B = {
    x: 123,
    y: () => { return 1 },
    z: 'hello'
}

合并interface可以定义多个相同的名称类型,并且会自动合并但是type别名只能取一个


interface A {
  a: number;
}
interface A {
  b: number;
}
const box: Box = {
  a: 123,
  b: 123, 
};

type中没有this

interface Foo {
    add(num: number): this
}
const f: Foo = {
    add:function(){
        return this
    }
}

我们知道,ts中class不仅可以当构造函数,还可以用于声明类

在js中,这份代码一定是可行的,但是在ts中会说没有name属性,那么我们就想到需要去声明一个类型用于限定一下这个class,但是转头一想,类型都是用来限定值(变量)的,现在拿一个类型来限定类型这合理吗?

_泛型inout_泛型instanceof


class Person{
    constructor(name){
        this.name = name
    }
}
let p = new Person('Tom')

因此,我们应该在自己身上去写类型

class Person{
    readonly age:number;
    name:string
    
    constructor(name:string){
        this.name = name
    }
}
let p = new Person('Tom')
p.name = 'Jerry'
p.age
p.age = 20 // 报错  只读属性

再来看一份代码,ts中的写法和java一样了

interface Country{
    name:string,
    capital:string
}
class Country2{
    name:string
    capital:string
}
class MyCountry implements Country,Country2{
    people:number = 14
    name='China'
    capital='Beijing'
}
let myCountry:MyCountry = new MyCountry()
myCountry.people
myCountry.name
myCountry.capital

interface和类声明的相同类型会合并

class A{
    x:number = 1
}
interface A{
    y:number
}
let a = new A()
a.y

泛型

我们并不知道传递来的参数是什么类型的数组,也不知道返回出来的值是什么类型因此也无法确定函数的类型

function foo(arr:any[]):any {
    return arr[0]
}

因此,我们需要ts自己明白传递的是什么类型,此时我们用到泛型(不在声明的时候确定类型,在调用的时候确定类型)

function foo(arr:T[]):T {
    return arr[0]
}
foo([1,2,3])  // T代表number
foo(['1']) // T代表string
function foo(arr1:T[],arr2:T[]):T[] {
    return arr1.concat(arr2)
}
foo<number|string>([1,2,3],['1','2'])

再看看稍微复杂一点的写法

function myMap (arr:T[],f:(arg:T)=>U):U[]{
    return arr.map(f)
}
myMap<string,number>(['1','2','3'],(n)=>parseInt(n))
// 泛型和interface一起用
interface Animal{
    name:T
    age:U
}
const an:Animal<string,number> = {
    name:'dog',
    age:2
}
const an2:Animal<number,string> = {
    name:3,
    age: 'cat'
}

小结

注意:我们定义类型,类型名记得大写

interface vs type

interface:对象模型,专门用于定义一个对象类型且定义对象和对象内部属性的接口

上文还介绍了一些泛型的基本用法,后续将会持续更新。