在TS中interface
和 type
都可以用来自定义数据类型,两者有许多相同之处,但是也有差别。我们一般选择 type
来定义基本类型别名、联合类型、元组等类型,而选择 interface
来定义复杂的对象、类、以及进行接口的继承。
1. 声明常见类型 和 方法
TS中常用的基本类型可以细分为两类:1. js已有类型,2.ts新增类型。
- JS 已有类型(原始类型):
原始类型 | 例子 | 描述 |
---|---|---|
number | 1,-22,1.3 | 任意数字 |
string | “af”,“JF” | 任意字符串 |
boolean | true, false | 布尔值 |
null | null | 空值 |
undefined | undefined | 未定义 |
symbol | symbol | symbol |
let a: number = 18;
let b: string = '字符串';
let c: boolean = true;
let d: null = null;
let e: undefined = undefined;
let f: symbol = Symbol();
- JS 已有类型(对象类型):
对象类型 | 例子 | 描述 |
---|---|---|
object | {age: 45} | 任意的js对象 |
array | [1,2,3] | 任意的js数组 |
function | (a,b)=>a+b | 函数类型 |
TS 新增类型:
类型 | 描述 |
---|---|
字面量 | 限制变量的值就是该字面量的值 |
any | 任意类型 |
unknown | 类型安全的any |
void | 没有值 |
never | 不能是任何值 |
tuple | 元组,固定长度数组 |
enum | 枚举 |
type | 类型别名 |
interface | 接口 |
interface 可以表示对象的各种语法,它的成员有5种形式。
- 对象属性
- 对象的属性索引
- 对象方法
- 函数
- 构造函数
对象的方法:
interface对象的方法共有三种写法。
第一种:参数后接冒号+类型,返回值类型在参数列表圆括号外
第二种:箭头函数形式
第三种:圆括号定义参数类型,参数外定义返回值类型
// 写法一
interface A {
f(x: boolean): string;
}
// 写法二
interface B {
f: (x: boolean) => string;
}
// 写法三
interface C {
f: { (x: boolean): string };
}
type对象的方法写法。
type A = (name: string) => string;
export type A = {
(name: string): string;
}
对象的方法:可以用来声明独立的函数
interface Add {
(x:number, y:number): number;
}
const myAdd:Add = (x,y) => x + y;
构造函数 interface内部使用new关键字,表示构造函数
interface ErrorConstructor {
new (message?: string): Error;
}
(1)定义基本类型
type Age = number;
interface Person {
name: string;
age: Age;
}
(2)定义函数类型
type Greeting = (name: string) => string;
type Greetingnum = {
(name: string): string;
}
interface Greeter {
(name: string): string;
}
(3)定义对象类型
type Point = { x: number; y: number };
interface Rectangle {
width: number;
height: number;
position: Point;
}
(4)定义泛型
T
是泛型变量,表示任何类型
type List<T> = {
data: T[];
add: (item: T) => void;
}
interface List<T> {
data: T[];
add: (item: T) => void;
}
1.interface
使用泛型的案例如下:
interface Container<T> {
value: T;
get(): T;
set(value: T): void;
}
class NumberContainer implements Container<number> {
value: number;
get() {
return this.value;
}
set(value: number) {
this.value = value;
}
}
const container = new NumberContainer();
container.set(42);
console.log(container.get()); //
2. interface 可以被类(class)实现(implement),而 type 不能
interface Animal {
name: string;
speak: () => void;
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
speak() {
console.log("hello!");
}
}
const myDog = new Dog("Sparky");
myDog.speak(); // 输出 hello
6.interface 可以定义多个同名接口并合并,而 type 不支持
interface User {
name: string;
age: number;
}
interface User {
gender: 'male' | 'female';
}
const user: User = {
name: '猫先生',
age: 25,
gender: 'male',
};
7.type可以使用 typeof 获取实例的类型,而 interface 不支持
type Person = {
name: string;
age: number;
}
const john: Person = {
name: "John",
age: 30,
}
type PersonType = typeof john; // 类型为 { name: string, age: number }
8、索引签名类型([key: type]: type
)
- 使得对象中可以出现任意多个属性
// [propName: string]: any 表示任意类型的属性
let h: {name: string, [propName: string]: any};
h = {name: "张三", age: 13, gender: "男"};
/*
1. 使用[key: string]来约束该接口中允许出现的属性名称。
2. 表示只要是string类型的属性名称,都可以出现在对象中。
3. 这样,对象 obj 中就可以出现任意多个属性
4. key 只是一个占位符,可以换成任意合法的变量名称。
5. 须知:js中对象的键是 string 类型的。
*/
interface AnyObject {
[key: string]: number;
}
let obj: AnyObject = {
a: 1,
b: 2,
}
2.interface继承
1. interface 支持 extends 实现接口的继承,而 type 不支持
(1)单接口继承
interface Animal {
name: string;
speak: () => void;
}
interface Pet extends Animal {
owner: string;
play: () => void;
}
class Dog implements Pet {
name: string;
owner: string;
constructor(name: string, owner: string) {
this.name = name;
this.owner = owner;
}
speak() {
console.log("speak:hello");
}
play() {
console.log(`${this.name} is playing with ${this.owner}`);
}
}
const myDog = new Dog("myPet", "Mr.Cat");
myDog.speak(); // 输出 "speak:hello"
myDog.play(); // 输出 "myPet is playing with Mr.Cat"
(2)多接口继承
1、type 只是类型别名,不能包含具体的属性和方法实现,因此它不支持通过 extends 关键字实现接口的继承。如果需要继承类型别名,需要使用交叉类型进行组合。
2、当你需要让一个接口继承多个其他接口时,使用 interface 更加方便。因为 interface 允许你使用逗号分隔的方式来继承多个接口,而 type 只能使用交叉类型(&)来实现继承。
interface Person {
name: string;
age: number;
}
interface Employee {
company: string;
jobTitle: string;
}
interface Manager extends Person, Employee {
teamSize: number;
}
const manager: Manager = {
name: 'John Doe',
age: 40,
company: 'ABC Inc.',
jobTitle: 'Manager',
teamSize: 10,
};
interface Person {name: string};
interface Contact {phone: string};
type PersonDetail = Person & Contact
let obj: PersonDetail = {
name: 'jack',
phone: '15698324'
}
// 使用交叉类型后,新的类型PersonDetail就同时具备了Person和Contact的所有属性类型。
// 相当于:
type PersonDetail = {name: string; phone: string;}
3、interface继承type
可以继承type命令定义的对象类型,如果其他类型则无法继承。
type Country = {
name: string;
capital: string;
}
interface CountryWithPop extends Country {
population: number;
}
4、interface 继承class
class A {
x:string = '';
y():boolean {
return true;
}
}
interface B extends A {
z: number
}
3.type继承
1、type 也可以继承 interface。
interface Foo {
x: number;
}
type Bar = Foo & { y: number; };
继承时,type 和 interface 是可以换用的。interface 可以继承 type。
type Foo = { x: number; };
interface Bar extends Foo {
y: number;
}
2.接口继承 type之间的继承
//&连接 两个必须都满足
type Person = {
age: string
}
type People1 = {
name: string
} & Person
|只能满足一个,两个不能同时满足
type People2 =
| {
name: string
}
| Person
4.class
1、封装
class Animal{
constructor(name){ //接收参数
this.name = name
}
run(){
console.log( this.name+'可以跑起来!')
}
}
console.log(111);
const dog = new Animal('小黑')
dog.run()
2、继承
1、使用extends关键字实现继承
2、子类可以继承父类中所有的方法和属性
3、子类只能继承一个父类(单继承),一个父类可以有多个子类
4、子类的构造方法中必须有super()来指定调用父类的构造方法,并且位于子类构造方法中的第一行
5、子类中如果有与父类相同的方法和属性,将会优先使用子类的(覆盖)
class Dog extends Animal{
bark(){
return `${this.name} 是一只狗`
}
}
console.log(222);
const mazi = new Dog('校长')
mazi.run()
console.log(mazi.bark)
3.多态
class JinMao extends Dog{
static categories = ['manmal'] //static-修饰符,静态属性
constructor(name){
super(name) //子类构造函数中必须用super()
consoe.log(this.name)
}
run(){
return 'memow'+super.run() //调用父类的run函数
}
}
console.log(333);
const maomao = new JinMao('maomao')
maomao.run()
//static 定义的变量和方法,可以直接用 方法名+点+变量/方法名() 调用
console.log( JinMao.categories );
一、ts新增的 class的方法
ts中的class又增加了三种修饰符,用来给类中的属性与方法设置权限,更易管理。
public:修饰的属性与方法是共有的,默认;
private:修饰的属性和方法是私有的,只能在class里使用,通过该类new出来的实例、继承的子类也不能使用;
protected:修饰的属性与方法是受保护的,继承的子类可以使用。
1、public
class Animal {
public name;
public constructor(name) {
this.name = name;
}
}
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
console.log(a.name); // Tom
2、private
class Animal{
private run(){
return `${this.name} is running`
}
}
const snake = new Animal()
console.log(snake.run()) //报错,run已变成私有方法,不能被使用
3、protected 继承的子类可以使用
class Animal {
protected name;
}
class Cat extends Animal {
constructor(name) {
super(name);
console.log(this.name);
}
}
4、readonly 只读属性
注意如果
readonly
和其他修饰符同时存在的话,需要写在其后面。
class Animal {
readonly name;
}
let a = new Animal();
console.log(a.name); // Jack
a.name = 'Tom'; //无法修改
5. interface可以扩展,type可以通过交叉实现interface的extends行为,interface可以extends type,同时type也可以与interface类型交叉 。
// interface通过extends实现继承
interface userName {
name: string;
}
interface user extends userName {
age: number
}
let stu:user = {name: 'wang', age: 10}
// interface的extends扩展可以通过type交叉(&)类型实现
type userName = {
name: string;
}
type user = userName & {age: number}
let stu:user={name: 'wang', age: 18}
// interface扩展type
type name = {
name: string;
}
interface user extends name {
age: number;
}
let stu:user={name: 'wang', age: 89}
// type与interface交叉
interface name {
name: string;
}
type user = name & {
age: number;
}
let stu:user={name:'wang', age: 18}
6.混合类型的 Interface
混合类型的接口就是使用同一个 Interface 来描述函数或者对象的属性或方法。
// 混合类型接口
interface MixType {
// 如果只有这么一个,那么这个接口是函数接口
(x: number, y: number): number,
// 还含有其他方法,那么这个接口就是混合接口
add(x: number, y: number): number,
// 还有另一个方法
log(): void,
(): void
}
// 调用
function sum() {
let sum: MixType = (() => { }) as MixType;
sum.add = (x: number, y: number) => { return x + y }
sum.log = () => { }
}
const isShowModal = ref(false)
function open() {
isShowModal.value = true
}
7.ts里面的 type 和 interface 的区别
1、区别
相同:
都可以用来定义 对象 或者 函数 的结构,而严谨的来说,type 是引用,而 interface是定义
不同:
1、type (alias)类型别名,可以定义基础类型、联合类型或交叉类型。interface 接口,只能定义对象,
2、接口可以 extends、implements,从而扩展多个接口或类。 type没有扩展功能,只能交叉合并
3、定义两个相同名称的接口会合并声明,定义两个同名的 type 会出现异常。
4、type 在声明类型别名之后实际上是一个赋值操作,它需要将别名与类型关联起来。也就是说类型别名不会创建出一种新的类型,它只是给已有类型命名并直接进行引用。interface是定义了一个接口类型