文章目录
TypeScript
中的接口可以用来描述对象外形,可以用来描述函数类型,也可以像java接口那样用来抽象方法。接下来会一一介绍。
描述对象外形
必需属性
interface Animal{
food:string;
size:string;
}
function printInfo(a:Animal){
console.log(a.food,a.size);
}
接口中,属性名右侧的:
表示是必需属性。
food:string
,food
是必需属性,且是字符串类型;size:string
,size
是必需属性,且是字符串类型。
因此,传入printInfo
的参数对象必须包含food
和size
这两个字符串属性,不能多,也不能少,必须刚刚好。否则,编译不过。
如果想多传属性呢?
有以下三种方法。
方法1 传参时不要使用对象字面量,使用一个变量
const animal = {
food:"meat",
size:"medium",
location:"south"
}
printInfo(animal);
方法2 使用字符串索引签名
interface Animal{
food:string;
size:string;
[propName:string]:any
}
printInfo({
food:"meat",
size:"medium",
location:"south"
});
[propName:string]:any
中的propName
是随便取的,[a:string]:any
、[b:string]:any
等等都行,只要你乐意。
字符串索引签名
const obj:MyObj = { a:"hello", b:"world" }
,obj["a"]
的值"hello"
,obj["b"]
的值是"world"
。
"a"
、 "b"
就是字符串索引
。
interface MyObj{
[propName:string]:string
}
const obj:MyObj = {
a:"hello",
b:"world"
}
使用字符串索引签名
,变量obj
中可以包含任意多的属性,只要属性名是string
类型,属性值是string
类型。
TypeScript
支持两种索引签名
:数字索引签名
和字符串索引签名
。
顺便了解下数字索引签名
。
数字索引签名
const arr=["hello","world"];
,arr[0]
的值是"hello"
,arr[1]
的值是"world"
。
0
和1
就是数字索引
。
接口可以用来描述对象的外形,数组也是对象啊。看看接口会怎样描述数组。
interface StringArray{
[index:number]:string
}
const arr:StringArray = ["hello","world"];
/*
const arr:StringArray = {
0:"hell0",
1:"world"
}
*/
[index:number]:string
就是数字索引签名
,index
也是随意取的。
变量arr
, 索引可以是任意数值,只要该索引对应的值是string
类型。
像const obj:MyObj = { 1:true, 2:"world" }
就不行,因为索引1
对应的值是boolean
类型。
虽然数字索引签名
可以用来描述数组,但并不常用。
要定义数组,下面两种方式更常见:
- 元素类型[],如
let arr:number[] = [1,2,3]
- 数组泛型,Array<元素类型>,如
let arr:Array<number> = [1,2,3]
方法3 使用类型断言
类型断言的关键字是as
。
类型断言其实是三十六计的“明修栈道,暗度陈仓”,欺骗编译器说,“看到没,看到没,传入的是Animal类型哈”,然而并不是,还偷偷地塞了个location
。
interface Animal{
food:string;
size:string;
}
function printInfo(a:Animal){
console.log(a.food,a.size);
}
printInfo({
food:"meat",
size:"medium",
location:"south"
} as Animal);
如果想少传属性呢?
方法1 类型断言
interface Animal{
food:string;
size:string;
}
function printInfo(obj:Animal){
console.log(obj.food,obj.size);
}
printInfo({
food:"meat"
} as Animal);
当然,依然可以借"类型断言"来"暗度陈仓"。但这样,缺点很明显:编译倒是过了,但真正运行的时候却出错了。因为最需要的东西,你恰巧没带。
所以 下面这种方法可能更好些。
方法2 可选属性
interface Animal{
food:string;
size?:string;
}
function printInfo(a:Animal){
console.log(a.food,a.size);
}
printInfo({food:"meat"});
printInfo({
food:"meat",
size:"medium"
})
接口中,属性名右侧的?:
表示是可选属性。
size
就是可选属性。调用printInfo
时,传入的对象参数时,size
可有可无。
除了必需属性、可选属性,还有只读属性。
只读属性
interface Animal{
readonly food:string;
size?:string;
}
var a:Animal = {
food:"meat",
size:"medium"
}
a.food = "grass"; //Cannot assign to 'food' because it is a read-only property
readonly
属性值允许在刚刚创建的时候赋值,之后就不能改动了。
明明吃肉长大的,忽然要人家改吃草,敢问:谁受得了!!
readonly
也可用于索引签名。
readonly
应用于数字索引签名
//数字索引签名
interface StringArray{
readonly [index:number]:string
}
let arr:StringArray = ["hello","world"];
arr[0] = "welcome";//Index signature in type 'StringArray' only permits reading
其实,如果想让数组只读,还有一种更简单的方式,使用ReadonlyArray<string>
。
let arr:ReadonlyArray<number> = [1,2,3];
arr[0] = 4;//Index signature in type 'readonly number[]' only permits reading.
readonly
应用于字符串索引签名
//字符串索引签名
interface StringArray{
readonly [propName:string]:string
}
let arr:StringArray = {
a:"hello",
b:"world"
}
arr["a"] = "world";//Index signature in type 'StringArray' only permits reading.
描述函数类型
interface SearchFunc{
(source:string,subString:string):boolean;
}
const find:SearchFunc = function(source,subString){
return source.search(subString) > -1;
}
const find2:SearchFunc = function(src,sub){
return src.search(sub)>-1;
}
(source:string,subString:string):boolean
的意思是,
a,函数接受两个参数,对参数名没有要求,可以叫"source",也可以叫"src",随便,都行;
b,第一个参数必须是|兼容string
类型,第二个参数也必须是|兼容string
类型;
c,函数必须有返回值,且返回值类型必须是boolean
类型。
接口继承接口
前面我们讲了,接口可以用来描述对象外形,可以用来描述函数类型。也就是说,接口就是一种类型。因此,接口继承接口,就是扩充了类型。
//动物
interface Animal{
food:string;
size:string;
}
//猫科动物
interface Feline{
location:string;
eat:()=>void;
}
//狮子
interface Lion extends Animal,Feline{
}
let lion:Lion = {
food:"meat",
size:"medium",
location:"Africa",
eat:function(){
}
}
接口继承类
类就是类型,接口也是类型。
所以接口继承类和接口继承接口一样,都是扩充类型。
//动物
class Animal{
food:string;
size:string;
}
//猫科动物
class Feline{
location:string;
eat:()=>void;;
}
//狮子
interface Lion extends Animal,Feline{
}
let lion:Lion = {
food:"meat",
size:"medium",
location:"Africa",
eat:function(){
}
}
类似java接口,用来抽象方法
接口中的方法全部是抽象方法,只有方法签名,没有方法体。
实现接口的类必须实现接口中的全部方法。
interface Animal{
eat();
}
class Lion implements Animal{
constructor(food:string){
}
eat(){
console.log("eating meat");
}
}
const lion:Lion = new Lion("meat");
lion.eat();