Skip to content

函数类型(函数签名)

接口能够描述JavaScript中对象拥有的各种各样的外形。 除了描述带有属性的普通对象外,接口也可以描述函数类型。接口描述函数类型也就是使用函数签名。通过接口描述函数类型,可以定义函数的参数类型、返回值类型以及函数本身的类型。为了使用接口表示函数类型,我们需要给接口定义一个调用签名。 它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。 在下面的示例中,我们定义了一个接口MyFunc,它表示一个函数类型。该函数接受两个参数x和y,它们的类型都是number,并且返回值的类型也是number。

ts
interface MyFunc {
  (x: number, y: number): number;
}

const myFunc: MyFunc = (a, b) => a + b;

console.log(myFunc(3, 4)); // 输出 7

然后,我们声明一个变量myFunc,并给它赋值一个函数表达式,该函数满足MyFunc接口的定义。在调用myFunc时,我们传递了两个数字参数,并打印了结果。 除了参数类型和返回值类型外,接口还可以描述函数的其他属性,例如函数的名称和可选属性等。例如:

ts
interface MyFunc {
  name: string;
  (x: number, y: number): number;
  optionalProp?: number;
}

const myFunc: MyFunc = (a, b) => a + b;
myFunc.name = "add";
myFunc.optionalProp = 42;

console.log(myFunc(3, 4)); // 输出 7
console.log(myFunc.name); // 输出 "add"
console.log(myFunc.optionalProp); // 输出 42

我们在MyFunc接口中添加了一个name属性和一个可选属性optionalProp。我们还可以给myFunc赋值一个函数表达式,并对接口中的属性进行赋值和访问。
使用接口描述函数类型可以提高代码的可读性和可维护性,同时还能充分发挥TypeScript的静态类型检查功能。
函数的参数会逐个进行检查,要求对应位置上的参数类型是兼容的。
如果你不想指定类型,TypeScript的类型系统会推断出参数类型,因为函数直接赋值给了MyFunc类型变量。
函数的返回值类型是通过其返回值推断出来的(此例是false和true)。
如果让这个函数返回数字或字符串,类型检查器会警告我们函数的返回值类型与MyFunc接口中的定义不匹配。

可索引的类型

与使用接口描述函数类型差不多,我们也可以描述那些能够“通过索引得到”的类型,比如a[10]或ageMap["daniel"]。 可索引类型具有一个索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。 让我们看一个例子:

ts
interface StringArray {
  [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

上面例子里,我们定义了StringArray接口,它具有索引签名。 这个索引签名表示了当用number去索引StringArray时会得到string类型的返回值。
共有支持两种索引签名:字符串和数字。 可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型。 这是因为当使用number来索引时,JavaScript会将它转换成string然后再去索引对象。 也就是说用100(一个number)去索引等同于使用"100"(一个string)去索引,因此两者需要保持一致。

ts
class Animal {
    name: string;
}
class Dog extends Animal {
    breed: string;
}

// 错误:使用'string'索引,有时会得到Animal!
interface NotOkay {
    [x: number]: Animal;
    [x: string]: Dog;
}

字符串索引签名能够很好的描述dictionary模式,并且它们也会确保所有属性与其返回值类型相匹配。 因为字符串索引声明了obj.property和obj["property"]两种形式都可以。 下面的例子里,name的类型与字符串索引类型不匹配,所以类型检查器给出一个错误提示:

ts
interface NumberDictionary {
  [index: string]: number;
  length: number;    // 可以,length是number类型
  name: string       // 错误,`name`的类型与索引类型返回值的类型不匹配
}
ts
interface ReadonlyStringArray {
    readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // error!

需要注意,你不能设置myArray[2],因为索引签名是只读的。

仅用于培训和测试,通过使用本站代码内容随之而来的风险与本站无关。版权所有,未经授权请勿转载,保留一切权利。
ICP备案号:滇ICP备15009214号-13   公安网备:滇公网安备 53312302000061号